一.介绍
1.1 JavaScript应用与不足
JavaScript是一门非常优秀的语言,有着广泛的应用:
- Web端、移动端、小程序端、桌面端、服务器端
JavaScript的缺点
- 使用var关键字的作用域问题
- 数组类型并不是连续的内存空间
- JavaScript没有类型检测机制
JavaScript的升级
- 从底层到应用层都在慢慢变好
- ES6的推出,使用JS更加现代、更新安全和方便
1.2 JavaScript类型的问题
错误出现的越早越好,这是编程开发中程序员的共识:
编码时 < 编译时 < 运行时 < 测试时 < 上线后
JavaScript代码的安全隐患:
:::info
function demo(mess){
console.log( mess.length )
}
demo(‘hello’) // 正常用调用ok
demo() // 没有参数隐患error
demo(100) // 类型不对隐患error
:::
问题:
- 没有对类型进行校验
- 没有对是否传参校验
1.3 关于 TypeScript
- TypeScript是微软2012年10月开发的一个开源的编程语言,当前最新版本为TypeScript 4.5
- TypeScript是JavaScript的一个超集, 扩展了JavaScript,为它添加了类型支持,来源于JavaScript,归于JavaScript
- TypeScript通过TypeScript编译器或Babel转译为JavaScript代码,
- TypeScript可以编译出普通、干净、完整的JavaScript代码
- 可运行任何浏览器,任何操作系统,任何可运行JavaScript的地方
1.4 为什么要用TypeScript
现在不会TypeScript的程序员,不是好的前端,前端程序员也要有类型思维
- 静态输入静态类型化是一种功能,可以在开发人员编写脚本时检测错误。查找并修复错误是当今开发团队的迫切需求。有了这项功能,就会允许开发人员编写更健壮的代码并对其进行维护,以便使得代码质量更好、更清晰。
- 大型的开发项目有时为了改进开发项目,需要对代码库进行小的增量更改。这些小小的变化可能会产生严重的、意想不到的后果,因此有必要撤销这些变化。使用TypeScript工具来进行重构更变的容易、快捷。
- 更好的协作当发开大型项目时,会有许多开发人员,此时乱码和错误的机也会增加。类型安全是一种在编码期间检测错误的功能,而不是在编译项目时检测错误。这为开发团队创建了一个更高效的编码和调试过程。
- 更强的生产力干净的 ECMAScript 6 代码,自动完成和动态输入等因素有助于提高开发人员的工作效率。这些功能也有助于编译器创建优化的代码。
二.TypeScript入门
2.1 TypeScript环境搭建
1、安装Node.js
安装文件下载地址:https://nodejs.org/en/download/。TypeScript源码需要进行编译以后才能运行,Node.js提供了编译环境。
2、安装TypeScript编译工具
- 安装好Node.js后,打开cmd窗口,输入以下命令
- 使用npm包管理工具下载TypeScript包并在全局环境下安装,安装成功后就可以通过tsc命令编译TypeScript源码。
- 可以通过tsc -v 命令查看当前TypeScript版本
2.2 TypeScript初体验
- 新建一个目录,在该目录下新建一个文件HelloWorld.ts,内容如下:
- 编译ts文件: tscHelloWorld.ts 这样就将ts文件编译成了js文件
- 这里将这个js文件放到html页面上进行测试,也可以使用node测试
- 生成的js文件可以用在各种项目中,通过这种方式可以积累自己的类库,方便做项目时快速开发。
2.3 工程配置
- 如果每次都手动运行一遍编译命令很麻烦,在开发中会设置为自动编译。
- 如果一个目录下存在一个tsconfig.json文件,那么它意味着这个目录是TypeScript项目的根目录。 tsconfig.json文件中指定了用来编译这个项目的根文件和编译选项。
- 在执行tsc时,编译器会在当前目录向父级目录逐级查找tsconfig.json文件,也可以使用命令行参数–project(或-p)指定一个包含tsconfig.json文件的目录
- 首先,在文件夹输入命令 tsc --init
- 会自动创建一个 tsconfig.json 文件
- 打开此文件,寻找 outDir 字段
- 将这一行注释解开,将 “./“修改为”./js”,保存
- 这代表着将编译的 .js 文件输出到当前目录下的 js 文件夹中,此文件夹会在有文件编译时自动创建
- 在当前目录下执行:tsc
tsc -w 对文件进行监视
2.4 Webstorm自动编译TypeScript设置
- 默认情况,WebStorm是提供了创建TypeScript的模版文件,但是不提供自动编译ts文件为js和map文件。
- 旧版本WebStorm需要额外配置一个File Watcher来对ts文件进行自动编译。
- 新版本的WebStorm已经提供自动编译的功能了,只是需要设置一下。
- 通过 File –> Settings,调出 Settings界面,然后选择右侧的界面即可配置。
打勾后默认是使用选择 Use tsconfig.json的设置方式的
此时,tsc 便处于监视状态,将 .ts 文件保存后会自动编译到 js 文件夹的 .js 中
2.5 ts-node 实验环境
- typescript自带的tsc命令并不能直接运行typescript代码。
- ts-node 并不等于 typescript 的 Node.js ,
- 仅仅封装了 typescript 的编译过程,提供直接运行typescript代码的能力。
- 安装:npm install -g ts-node
- ts-node 文件名.ts
三. TypeScript配置项
3.1 TypeScript文件指定
选项字段 | 类型 | 默认值 | 说明 |
---|---|---|---|
files | array | [] | 可以单独设置ts需要编译哪些文件 |
include | array | [] | 指定哪些ts文件需要被编译, 例如:“./src/**/*” |
exclude | array | [“node_modules”,“bower_components”,“jspm_packages”] | 表示不包含 |
extends | string | ‘’ | 表示继承配置文件 |
3.2常用编译选项
四. TS基础语法
4.1 TS的类型声明
1. 先声明变量 再赋值
let a : boolean ;
a = false;
2. 声明的同时进行赋值
let b : number = 2;
**3. 这算是第二种的简写 **
声明和赋值同时进行ts会自动为我们进行声明
let c = false;
c = 1; //此时也会报错
4. 函数的参数声明和返回值类型声明
//js中的函数是不会考虑参数的数量和类型的
function fun(num1**:number**,string1**:string**):string {
console.log(${num1}和${string1}
);
return${num1}和${string1}
}
fun(1,“number”);
//最后一个string是该函数的返回值
4.2 TS的基础类型
数据类型 | 关键字 | 描述 |
---|---|---|
任意类型 | any | 声明为 any 的变量可以赋予任意类型的值。 |
数字类型 | number | 双精度 64 位浮点值。它可以用来表示整数和分数。 |
let binaryLiteral:number=0b1010; // 二进制 | ||
let octalLiteral:number=0o744; // 八进制 | ||
let decLiteral:number=6; // 十进制 | ||
let hexLiteral:number=0xf00d; // 十六进制 | ||
字符串类型 | string | 一个字符系列,使用单引号(')或双引号(")来表示字符串类型。反引号(`)来定义多行文本和内嵌表达式。 |
let name:string=“eduwork”; | ||
let years:number=5; | ||
let words:string=您好,今年是 ${ name } 发布 ${ years + 1} 周年 ; | ||
布尔类型 | boolean | 表示逻辑值:true 和 false。 |
let flag:boolean=true; | ||
数组类型 | 无 | 声明变量为数组。 |
// 在元素类型后面加上[] | ||
let arr:number[] = [1,2]; | ||
// 或者使用数组泛型 | ||
let arr:Array = [1,2]; | ||
元组 | 无 | 元组类型用来表示已知元素数量和类型的数组,各元素的类型不必相同,对应位置的类型需要相同。 |
let x:[string,number]; | ||
x =[‘EduWork’,1]; // 运行正常 | ||
x =[1,‘EduWork’]; // 报错 | ||
console.log(x[0]); // 输出 EduWork | ||
枚举 | enum | 枚举类型用于定义数值集合。 |
enum Color {Red,Green,Blue}; | ||
let c:Color=Color.Blue; | ||
console.log©; // 输出 2 | ||
void | void | 用于标识方法返回值的类型,表示该方法没有返回值。 |
function hello():void { | ||
alert(“Hello EduWork”); | ||
} | ||
null | null | 表示对象值缺失。 |
undefined | undefined | 用于初始化变量为一个未定义的值 |
never | never | never 是其它类型(包括 null 和 undefined)的子类型,代表从不会出现的值。 |
4.2.1 number类型
数字类型统一为number, TypeScript和JavaScript一样,不区分整数,浮点和双精度(int,float, double)
let binaryLiteral:number=0b1010; // 二进制
let octalLiteral:number=0o744; // 八进制
let decLiteral:number=6; // 十进制
let hexLiteral:number=0xf00d; // 十六进制
4.2.2 boolean类型
表示逻辑值:true 和 false。
let flag:boolean=true;
flag = 50 > 30;
flag = !!100
4.2.3 string类型
一个字符系列,使用单引号(')或双引号(")来表示字符串类型。反引号(`)来定义多行文本和内嵌表达式
let name:string=“eduwork”;
let years:number=5;
let words:string=您好,今年是 ${ name } 发布 ${ years + 1} 周年
;
4.2.4 数组
/*
- 语法:类型[];
- Array<类型>
- */
let arr : string[]; //表示字符串数组
let arr2 : number[]; //表示数值数组
let arr3 : Array; //这种方式跟上面那种相同
4.2.5 null和undefined
null | null | 表示对象值缺失。 |
---|---|---|
undefined | undefined | 用于初始化变量为一个未定义的值 |
let a:null = null;
let b:undefined = undefined;
4.2.6 any 表示任意类型
any表示任意类型 一个变量设置any相当于对该变量关闭ts的类型检测 不建议使用
let d : any;
let e; //声明变量不指定类型,则ts解析器会自动判断变量的类型为any(隐式的any)
d=10; d=“as”; d=true;
4.2.7 unknow 表示未知类型
unknow 表示未知类型, 是一个类型安全的any 不能直接赋值给其它变量
let f : unknown;
f=10;f=“as”;f=true;
let s :string;
//any可以将任意值都赋给其它变量 所以很危险不仅搞自己还把别人也搞了
s =d;
// s = f; //unknow就不行,此时会有下波浪线提示
unknown 比 any 安全 ,因为它不能赋给其他除 unknown和 any 类型之外的变量,如果想要赋值给其他类型的变量,则需要把范围缩小
//第一种通过判断
if(typeof f === “string”){
s = f;
}
//第二种通过断言
s = f as string;
//第三种<>
s = f; //表达意思是一样的 都是表达当f为string时才给s赋值
4.2.8 void
void用来表示空,以函数为例,表示没有返回值的函数
function fun():void {
// return 123; //此时再返回就会报错
}
4.2.9 never
never 表示永远不会有返回结果
never类型的函数内部必须有一个永远执行下去的代码段,永远也走不出去
function fun2() 😗* never **{
/while(true){
}/
//像这种直接报错没有返回值的
throw new Error(“直接报错!”);
}
4.3 TS中的对象类型声明
object 表示一个对象, 但是在js中万物皆对象 function、 array等
- {}用来指定对象中可以包含那些属性
- 语法:{属性名:属性值,属性名:属性值}
- 在属性名后边加上?,表示属性是可选的
- [propName:string]:any表示可以任意类型的属性 any换成number表示其余类型的值只能是数字
let obj : object;
obj = {};
obj = function () {};
let obj2 : {name:string,age?:18};
obj2 = {name:‘ad’};//此时age就可写可不写
let obj3 :{name:string,[propName:string]:any};
obj3 = {name:‘sda’,age:18,sex:‘男’};
4.3 TS中的函数类型声明
设置函数结构的类型声明
语法:(形参:类型,形参:类型…) => 返回值的类型
let fuc : (a:number,b:string) => string;
fuc = function (n1,n2):string {
return "asd";
};
4.4 联合类型
可以使用 | 连接多个类型
let b : "sex" | "girl";
b = 10; // 此时b就不能再等于其他值,要么是sex要么就是girl
//这样写也可以要么是布尔值要么是字符串类型
let c : boolean | string;
c = true; c = "haha";
c = 12; //不能为数字
//联合类型
let info: string | number; //可以是字符串和数值型
info = "abc"
info.toLowerCase();
info = 20
info.toFixed()
// info = true ;//只能是字符串和数值型
let demo2: string | null | undefined
demo2 = null
demo2 = undefined
let demo6: string
// demo6 = null;
// demo6=undefined
function fun(a: number | string, b: number | string): void | undefined | number | null {
return undefined
}
let arr5: (number | string)[] = ["aaa", 111]
arr5.push('hello')
arr5.push(123)
arr5.push('bbb')
let user1: { name: string } & { age: number };
user1 = {
name: 'zhangh', //单独只有一个属性不可以 必须两个都有
age: 20
}
//常量
let num: 10
let str: 'hello'
str = 'hello'
num = 10
let sex: '男' | '女'
// sex = '人妖'//只能为男或女
sex = '男'
let state: 1 | 2 | 3 | 4 | 5;
// state = 6
4.5 &同时
&表示同时
//此时要同时满足name为string类型age为number类型
let j : {name:string} & {age:number};
//必须要有name和age少一个或者类型不对都会报错
j = {name:‘jsjsj’,age:18};
let user1: { name: string } & { age: number };
user1 = {
name: 'zhangh', //单独只有一个属性不可以 必须两个都有
age: 20
}
4.6 字面量进行类型声明
字面量进行类型声明
let a : 10;
a = 11;//此时a就只能等于10不能再是其它值
let sex: ‘female’ | ‘male’ // 只能使用固定值
4.7 元组
元组 可以限制长度和每个元素类型的数组
let array1: string[] = ['a', 'b', 'c']
let array2: (string | number)[] = ['aa', 'bb', 'cc', 'dd', 20, 10, 5]
//元组 可以限制长度和每个元素类型的数组
let array3: [string, string, string, number] = ['a', 'b', 'c', 4]
let array4: [string, number][] = [ //二维数组
['zhangsan', 10],
['lisi', 15],
]
4.8 enum枚举
//在固定值中选择 -- 联合类型字面值方法
let sex1: 'famale' | 'male'
let state1: 1 | 2 | 3 | 4 | 5
//用来在固定值中选择 -- 枚举方法
enum sex2 {
Famale, // 这里相当于0
Male // 这里相当于1
}
console.log(sex2.Famale); //0
console.log(sex2.Male); //1
console.log(sex2[0]); //Famale
console.log(sex2[1]); //Male
4.9 类型的别名
//别名 关键字 type
type mystate = 1 | 2 | 3 | 4 | 5
let state3:mystate
state3 = 1
type myvar = string|boolean|number
function fun5(a:myvar,b:myvar,c:myvar){
}
type myreturn = null|undefined|void|string|number
let fun6:(a:myvar,b:myvar)=>myreturn
type myfun = (a:number,b:number)=>myreturn
let fun7:myfun=(a,b)=>a*b
fun7(3,5)
type myobj = {name:string,age:number}
let person:myobj={name:'张行',age:23}
4.10 类型断言type assertions
- TypeScript 中的 type assertions 的,它与其他语言中的类型强制转换有相似之处,并通过 as 运算符执行。
- 通过类型断言这种方式可以告诉编译器,“相信我,我知道自己在干什么”,你会比 TypeScript 更了解某个值的详细信息,你清楚的知道一个实体具有比它现有类型更确切的类型 — 断定
- 尖括号语法
- let someValue: any = “this is a string”;
- // someValue是any任何类型的实体,在具体应用的时候使用了断言 someValue肯定是一个字符串类型
- let strLength: number = (someValue).length;
- as 语法
- let someValue: any = “this is a string”;
- // someValue是any任何类型的实体,在具体应用的时候使用了断言assomeValue肯定是一个字符串类型
- let strLength: number = (someValue as string).length;
4.11 类型断言 as const应用
- 根据具体的值转化类型,推断类型转化为字面值类型:
- let str = ‘eduwork’**as const **
- **相当于 **let str:‘eduwork’= ‘eduwork’
- 不能给其他值
- 推断类型的数组转化为元组
- 推断的对象可以转化为readonly的
- 在解构中使用as const
function demo(n:number|string){
let len:number
/*if (typeof n==='string'){
len= n.length
console.log(len)
}*/
// len=(<string>n).length
//类型断言 相当于强制类型转换
len = (n as string).length
console.log(len)
}
demo('www.example.com')
// const abc = "www" //常量 不可以二次赋值
let abc:'eduwork' = 'eduwork' //字面量 //可以二次赋值 但是只能赋固定值
let aaa = 'itzhangh' as const //转成字面量 //注意 不是转成常量
// aaa = 'zhangsan'
aaa = 'itzhangh'
let arr3=['www',14] as const //转换成 "只读" 的 ”元组“
let arr4=<const>['www2',15] //转换成 "只读" 的 ”元组“
// arr3.push('abc')
console.log(arr3[0])
console.log(arr3[1])
console.log(arr4[0])
console.log(arr4[1])
let user3={
name:'zhangh',
age:20
} as const //转成 只读 对象
// user3.name='zhangsan'
console.log(user3.name)
function ew() {
let str: string = 'www.eduwork.cn'
let fun = (a: number, b: number): number => a + b
// return [str, fun] as [string,Function]
// return [str, fun] as [typeof str,typeof fun]
return [str, fun] as const
}
// let [nstr,mfun]=ew() as [string,Function]
// let [nstr,mfun]=ew() as [string,(a:number,b:number)=>number]
let [nstr,mfun]=ew()
// console.log((mfun as (a:number,b:number)=>number)(100,200))
4.12 非空断言(!)应用
{
let str: string | null | undefined = 'eduwork.cn'
str = 'abc'
str = null
str = undefined
//
/* let el:HTMLDivElement = document.querySelector('.box') as HTMLDivElement
el.innerHTML= '这是非空断言测试'*/
// ! 断言成非空
let el: HTMLDivElement = document.querySelector('.box')!;
el.innerHTML = '这是非空断言测试'
let flag:boolean = true
let btn:HTMLButtonElement = document.querySelector('#btn')!
btn.addEventListener('click', (e:Event):void =>{
console.log(e)
flag = !flag
if (flag){
document.body.style.background="#ffffff"
btn.innerHTML = '关灯'
}else{
document.body.style.background="#000000"
btn.innerHTML = '开灯'
}
})
}