day01
1.什么是ts ts可以理解为JavaScript的超集,它是由微软公司开发的一种编程语言,可以运行在任何浏览器还有操作系统
2.全局安装ts的命令是: npm i -g typescript
3.ts的优点 *1.灵活:可以将代码自动转换为js代码 *2.兼容性强: 可以在任何浏览器和操作系统运行,并不需要浏览器的支持,通过node.js运行即可 *3.方便维护: 在ts中的报错在编译时就能发现,不会直接显示到用户页面,
4.ts的缺点 不利于前端工程师上手,需要理解接口,枚举等类型的概念,需要多写一些类型的定义,工作量大,和一些库不能完美结合
5.ts分为动态类型和静态类型: 动态类型就是在运行时才会报错,javascript是解释型的语言,没有编译阶段,所以属于动态类型 静态类型是在编译阶段就能确定每个变量的类型,如果类型不对就会直接报错,ts的话在编译阶段就会检查每个类型属于静态类型
6.强类型和弱类型语言的主要区别就是靠是否能隐式转换来分类的,ts和jacascript都属于弱类型
7.ts的数据类型 *1.数字类型 语法: let num: number = 5 十进制: let decLiteral: number = 6 十六进制: let hexLiteral: number = 0xf00d es6的二进制: let binaryLiteral: number = 0b1010 es6的八进制表示法: let octalLiteral: number = 0o744 无穷大: let infinityNumber: number = Infinity *2.布尔类型 语法: let isDone: boolean = false(true) *3.字符串类型 语法: let myName: string = '啦啦啦' 用法: let myAge: number = 20 let sentence = My name is ${myName}, My age is ${myAge} 在浏览器页面显示: docment.body.innerHTML = sentence *4.数组类型: *1.语法: let array: number[] = [1,2,3,4] let arratString: string[] = ['1','2','3'] *2.数组泛型的语法: let arrayList: Array = [1,2,3,4] let listString: Array = ['1','2','3'] *5.未定义和空类型 *1.未定义语法: let a : undefined = undefined *2.空类型: let b: null = null *6. 对象类型 *1.语法: let obj: {name: string, age: number} let obj2: {name: string, age: number} obj = {name: '党少龙', age: 20} let info = 'My name is {obj.age}'
*7.元组类型
*1.语法: let tom: [string, number] = ['Tom', 25];
*2.赋值或访问已知索引元素: let tom: [string, number];
tom[0] = 'Tom';
tom[1] = 25;
tom[0].slice(1);
tom[1].toFixed(2)
*8.枚举:
*1.语法:enum Color {
Red = 1,
Blue = 3,
Yellow = 4 } let c: Color = Color.Red console.log(c); *9.any可以赋任何值 语法:let value: any; value = 123; value = "abc"; value = false; *10. void类型 *1.不用return返回: function noReturn(): void { console.log('My name is void'); } *2.需要return返回:function haveReturn(): string { return '55' } *11.never类型: *1. 返回never的函数: function error(message: string): never { throw new Error(message); } *2.推断: function fail() { return error("Something failed"); }
11.交叉类型(&)
交叉类型就是取多个类型的并集,使用 & 符号定义,被&符链接的多个类型构成一个交叉类型,表示这个类型同时具备这几个连接起来的类型的特点
12.联合类型(|) 满足其中一个即可
/** * 联合类型 */ let allType: number | string allType = 1; allType = "eddd" // 不能将类型“boolean”分配给类型“string | number”。 //allType = false
13.类型断言
类型断言
有时候一个数据的值是多变的,并不是单一,这个时候我们就要告诉编译器,我知道我要什么,我自己检查了,不需要你检查.我自己定义他的类型
类型断言有两种写法
1. 其一是“尖括号”语法:
``` typescript
/***
* 类型断言
* 尖括号写类型断言
*/
let someValue: any;
someValue = 123;
someValue = "dddd";
let someValueLength = (<string>someValue).length
2. as写法
```typescript
/**
* 第二种 作为as进行编写
*/
let someName: any;
someName = 123
someName = '123'
let someNameValueLength = (someName as string).length
day03
索引类型**
• 1)绕开多余属性时,[]中间的内容是可变的
• 2)数组模式:如果想要东西不可被修改,只能读取,那么就使用readonly
**接口继承**(extends)
• 1)减少了代码量、提高额接口的可复用性,一个接口可以继承多个,用逗号隔开
• 2)①原型链法:问题--当原型中存在引用类型值时,实例可以修改其值
②仅继承父构造函数的原型对象:
优点:1.不需要新建对象实例 2.不需要遍历原型链
缺点:子对象的修改会影响到父对象
• ③借用构造函数:可以解决原型中引用类型值被修改的问题
• 缺点:1.只能继承父实例属性和方法,不能继承父原型属性和方法
• 2.无法实现函数复用
• ④组合继承:优点:1.可以复用原型上定义的方法
• 2.保证每个函数有自己的属性,解决原型中引用类型值被修改的问题
• ⑤原型式继承:缺点:原型中引用类型值会被修改、无法传递参数
• ⑥寄生式继承:在原型式继承的基础上,通过封装继承过程的函数增强对象,返回对象
• ⑦寄生组合式继承
• ⑧Class继承
**闭包**
• 1)外部函数不能访问内部函数的作用域,内部函数可以访问外部函数
• 2)闭包可以形成一个块级作用域,用来保存变量
• 3)可以隔离作用域,避免全局污染,但是容易导致内存泄露
• 4)闭包的返回值必须式一个回调函数
**混合类型接口**
• 1)js类型式灵活的,函数是对象类型,对象里也可以有属性,也就是说有时一个对象既是函数,也包含一些属性
• 2)好处:
1.变量永久保存,不会被污染
• 2.变量只是内部使用
• 3.可以定义每个类型,方便维护
day04
**构造函数**
• 1)构造函数本质上是个普通函数,充当类的角色,主要用来创建实例,并初始化实例,即为实例成员变量赋初始值
• 2)普通函数是直接调用,而构造函数需要使用 `new` 关键字来进行调用
• 3)如果想要使用显式的返回值,则显式的返回值必须是对象
**原型**
• 1)原型就是每个构造函数都有prototype属性,指向另一个对象,所有对象都有一个proto属性,指向构造函数的prototype原型对象
• 2)作用就是让同一个方法在内存中只有一份,节省空间,优化性能
**原型链**
• 万物皆对象
• 原型链就是访问一个对象时,先查找这个对象自身有没有该属性,没有就找原型,还没有就找原型对象的原型,一直到object为止
**栈和堆**
• 1)栈存放基本数据类型
• 2)堆存放复杂数据类型
• 3)栈先进先出,堆先进后出
html5新增的特性:
一、html5新特性——canvas元素
canvas元素用于在网页上绘制图形,有多重绘制路径、矩形、圆形、字符以及添加图像的方法
svg元素用于描述二维是矢量图形的一种图形格式。
(1)把svg直接当成图片放在网页上
(2)实现动画
(3)svg图片的交互和滤镜效果
不同点:canvas是通过js来绘制2d图形,逐像素进行渲染的,假若在图片完成后进行修改,整个场景就会重新绘制
svg元素是使用XML描述2d图形的语言,svg dom中的每一个元素都是可用的,可以为其添加js处理器。每一个被绘制的图形均被视为对象,如果发生变化,浏览器就会自动重新绘制图形
二、html5新特性——表单元素
1)新增的表单元素
<datalist>:元素规定输入域的选项列表,使用<input>元素的list元素与<datalist>元素的id绑定
<keygen>:提供一种检验用户的可靠方法,标签规定用于表单的密钥对生成器字段
<output>:用于不用类型的输出,比如计算或脚本输出
2)新增的表单属性
placehoder属性:简短的提示在用户输入值前会显示在输入域上,既默认框提示
required属性:是一个boolean属性,要求填写的输入域不为空
pattern属性:描述了一个正则表达式用于验证<input>元素的值
max / min属性:最大最小值
step属性:为输入域规定合法的数字间隔
height / width属性:用于image类型的<input>标签的图像高度和宽度
autofocus属性:是一个boolean属性,在页面加载时自动获得焦点
multiple属性:是一个boolean属性,规定<input>元素中选择多个值
三、html5新特性——媒体元素
1)播放音频文件的元素<audio>————<audio controls>
(1)control属性提供播放暂停和音量控件
(2)<audio>和<audio/>之间插入浏览器不支持的<audio>元素的提示文本
(3)允许使用多个<source>元素用来链接不同的音频文件,浏览器使用第一个支持的音频文件
(4)支持三种音频格式文件:mp3、wax、ogg
2)播放视屏文件的元素<video>
(1)control属性提供播放暂停和音量控件,也可以使用dom操作:play()和pause()
(2)video元素提供了width和height控制视频的尺寸。如果设置了就会在页面加载时保留,没设置就不保留,页面根据原始视频改变
四、html5新特性——地理定位
HTML5 Geolocation(地理定位)用于定位用户的位置
五、html5新特性——html5拖放
六、html5新特性——web存储
(1)localStrorage——没有时间限制的数据存储,存在本地
(2)sessionStrorage——有时间限制的数据存储,针对一个session,本次会话结束(关闭浏览器)数据删除
七、html5新特性——应用程序缓存(Application Cache)
引入应用程序缓存,意味着web应用可进行缓存,并可以在没有网络是访问
优势:
(1)离线浏览——用户可在应用离线时使用
(2)速度——已缓存的加载更快
(3)减少服务器负载——浏览器将只从服务器下载更新过或更改过的资源
八、html5新特性——html5 Web Workers
当HTML页面中执行脚本时,页面的状态是不可响应的,直到脚本已完成。但是web workers是运行在后台的js,不会影响页面的性能,可以一直在后台运行
九、html5新特性——html5服务器发送事件
允许网页获得来自服务器的更新,现在可以做到自动更新
十、html5新特性——html5 WebSocket
```
```
day05
type和interface的区别:
### 1. 定义的不同
**interface**:接口,TS 设计出来主要用于定义【对象类型】,可以对【对象】的形状进行描述。
**type** :类型别名,为类型创建一个新名称。它并不是一个类型,只是一个别名。
类型别名可以起到类似接口的作用。但是,有一些细微的差别。主要区别在于 type 一旦定义就不能再添加新的属性,而 interface 总是可扩展的。
### 2. 使用的区别
1. interface: **接口可以重复声明**,TS会将它们合并。
2. type的使用(可以定义基本类型,联合类型,元组类型)
2.1 基本类型
type StringType = string
2.2 联合类型
type paramtype = number | string
2.3 元组类型
type arrType = [string, string, number]
2.4 定义函数类型--类型别名
type AddFunc = {name: string, age: number}
### 3. 总结:
1、如果需要被 extends 或者 implements, 则尽量使用**接口**。
2、如果需要使用联合类型或者元组类型,**类型别名**会更合适。
3、如果是定义对象或函数,则都可以。
4、如果实在不想选择的话,就能用interface实现,用interface,如果不能就用type。
###4. **相同点
1.都可以描述一个对象或者函数
1)interface
interface User {name: string, age: number}
interface SetUser {(name: string, age: number): void;}
2)type
type User = {name: string, age: number};
type SetUser = (name: string, age: number): void;
2.都允许继承(官网话叫拓展 extends)
interface 和 type 都可以拓展,并且两者并不是相互独立的,也就是说 interface 可以 extends type, type 也可以 extends interface 。 虽然效果差不多,但是两者语法不同:
type:
不一样的点:
1. type是赋值,进行别名的修改
2. interface 声明一个类型
3. type 可以声明基础类型数据, interface只能声明对象
4. interface可以使用extends进行继承,但是type不可以,因为是类型别名,属于复制的一种
5. interface 可以重复声明,自动合并一起,
6. type不可以重复声明
相同点:
1.type和interface都可以声明对象和类型
2.type声明值类型,做类型判断的
3.interface 只能声明对象,不能声明基础类型,所以校验的函数参数只能是对象
函数类型定义:如果省略参数类型,默认是any
1.为函数定义类型:我们可以给函数定义类型,这个定义包括对参数和返回值的类型定义
(如果在这里省略参数的类型,TypeScript 会默认这个参数是 any 类型;如果省略返回值的类型,如果函数无返回值,那么 TypeScript 会默认函数返回值是 void 类型;如果函数有返回值,那么 TypeScript 会根据我们定义的逻辑推断出返回类型。)
2.完整的函数类型:一个函数的定义包括函数名、参数、逻辑和返回值。我们为一个函数定义类型时,完整的定义应该包括参数类型和返回值类型。(函数中如果使用了函数体之外定义的变量,这个变量的类型是不体现在函数类型定义的。)
3.使用接口定义函数类型:可以清晰的定义函数类型
4.使用类型别名:使用`type`关键字可以为原始值、联合类型、元组以及任何我们定义的类型起一个别名(使用类型别名定义函数类型更直观易读)
函数参数的三个知识点:
1.可选参数?:可选参数在JavaScript中可以实现,TypeScript中需要在该参数后面加个`?`,且可选参数必须位于必选参数后面;(接口形式定义的函数类型必选参数和可选参数的位置前后是无所谓的,但是今天学到的定义形式,可选参数必须放在必选参数后面,这和在 JS 中定义函数是一致的。)**在对象中使用**
2.默认参数:直接给形参赋值,没限制的话就根据写的来返回
是在ES6标准中添加的语法,为函数参数指定默认参数,写法就是在参数名后面使用`=`连接默认参数(可选参数和带默认值的参数在函数调用时都是可以不传实参的,但是区别在于定义函数的时候,可选参数必须放在必选参数后面,而带默认值的参数则可放在必须参数前后都可。当我们为参数指定了默认参数的时候,TypeScript 会识别默认参数的类型;当我们在调用函数时,如果给这个带默认值的参数传了别的类型的参数则会报错:)
3.剩余参数:如果定义一个函数可以输入任意个参数,那我们在定义参数列表的时候无法挨个定义,es6发布前,我们用arguments来获取参数列表
这也是在ES6中添加的语法,可以使用`...参数名`来获取剩余任意多个参数,获取的是一个数组。
函数重载:着重强调的是,这里的函数重载区别于其他语言中的重载,TypeScript中的重载是为了针对不同参数个数和类型,推断返回值类型。
**day06泛型**
**1.泛型**
1.泛型的概念:指在定义函数,接口或类的时候,不预先指定具体的类型,而在使用的时候再指定类型的一种特性。
2.使用标识符号 **<T>**
3.表示一个值可以为任意类型的时候,则指定它的类型为any
**2.泛型变量**
当我们使用泛型的时候,你必须在处理类型涉及到泛型的数据的时候,把这个数据当做任意类型来处理。这就意味着不是所有类型都能做的操作不能做,不是所有类型都能调用的方法不能调用。
**3.泛型函数类型**
**4.泛型约束**
当我们使用了泛型时,就意味着这个这个类型是任意类型。但在大多数情况下,我们的逻辑是对特定类型处理的。
泛型约束就是使用一个类型和`extends`对泛型进行约束
**5.小节**
使用泛型来弥补使用any造成的类型信息缺失;当我们的类型是灵活任意的,又要准确使用类型信息时,就需要使用泛型来关联类型信息,其中离不开的是泛型变量;泛型变量可以是多个,且命名随意;如果需要对泛型变量的类型做进一步的限制,则需要用到我们最后讲的泛型约束;使用泛型约束通过`extends`关键字指定要符合的类型,从而满足更多场景的需求。
**6.类**
注意在声明类的时候,需要对类的属性的数据类型进行约束
1.类的定义
- ```
1.ES6中类的定义
// 声明人的类
class People {
// 类的属性
constructor(name, age) { // 构造器,实例化方法的时候触发
this.name = name
this.age = age
}
// 类的方法
sport(){
return this.name + '会运动'
}
}
对类进行实例化
let p = new People('小明',18)
调用类的方法
console.log(p.sport()); //小明会运动
获取类的属性
console.log(p.age); // 18
2.TS中类的定义
3.类的继承
1.ES5中的继承
在ES5中继承可以通过原型链来实现继承(原型链继承,原型链加冒充对象的继承方式,组合继承)
2.ES6中的继承
3.TS中类的继承
和ES6中的继承一样,只是添加了属性的数据类型
4.类的修饰符
定义属性的时候提供了三种修饰符:
1.public 公有,类里面、子类、类外面都可以访问
2.protected 保护类型 类里面、子类可以访问 类外面不可以访问
3.private 私有类型 类里面可以访问,其他不行
如果不加修饰符,默认是public:
```
**7.静态属性和静态方法** 1.静态属性 使用static修饰静态属性 (静态属性不能在实例上获取) 2.静态方法 静态方法不能在实例上获取
**8.多态**
1. 多态的定义 父类定义一个方法不去实现,让继承他的子类去实现,每一个子类有不同的表现
2.多态的实现
1. 首先声明一个父类,父类中声明一个方法,不去实现
2.声明一个类继承父类,并且实现 eat 方法
3.再声明一个类继承父类,并且实现 eat 方法
**9.修饰符**
1. public
public`表示公共的,用来指定在创建实例后可以通过实例访问的,也就是类定义的外部可以访问的属性和方法。默认是 public,但是 TSLint 可能会要求你必须用修饰符来表明这个属性或方法是什么类型的。
2.private
private`修饰符表示私有的,它修饰的属性在类的定义外面是没法访问的:
3.protected
protected`修饰符是受保护修饰符,和`private`有些相似,但有一点不同,`protected`修饰的成员在继承该类的子类中可以访问
protected`还能用来修饰 constructor 构造函数,加了`protected`修饰符之后,这个类就不能再用来创建实例,只能被子类继承,这个需求我们在讲 ES6 的类的时候讲过,需要用`new.target`来自行判断,而 TS 则只需用 protected 修饰符即可:
4. readonly 修饰符
在类里可以使用`readonly`关键字将属性设置为只读。 设置为只读的属性,实例只能读取这个属性值,但不能修改。
**泛型**
• 是指在定义函数或者接口的时候,不先制定具体类型,而在使用时再制定类型
• 1)写法:<任何大写字母>,---> 一般用<T>表示
• 3)泛型多用于函数中
**泛型变量**
• 1)使用泛型时,不是所有属性都能操作
• 2)需要考虑当前传的参数是否有这个属性
**泛型函数的类型**
• 1)可以使用类型别名来定义,也可以用interface来定义
• 2)一个接口中可以定义多个类型
• 3)可以把接口中泛型变量提升到最外层,接口中都可以使用这个泛型变量了
**泛型约束**
• 就是对特定类型进行处理
• 可以使用继承extends,输出的一定要包含继承过来的属性
**泛型中使用类型参数**
• keyof是用来检查的
**类**
• 1)类其实就是继承
• 2)声明类的时候,需要对类的属性的数据类型进行约束
**类的继承**
• 1)es6继承:extends来继承,super来承接父辈的属性
• 2)类:和es6一样,只是添加了属性的数据类型
**类的修饰符**
• 1)public:公共的,类里面、子类、类外面都可以访问
• 2)protected:保护类型,类里面、子类可以访问,类外面不能
• 3)privated:私有类型,类里面可以访问,其他不行
• 4)readonly:只读属性,只能读取不能修改
**静态属性**
• 使用static修饰静态属性,不能再实例上获取
**静态方法**
• 不能在实例上获取
**可选类属性**
• 类也可以使用 ?来标记表示为可选属性
**多态**
• 父类定义一个方法不去实现,让继承的子类去实现,每个子类有不同的表现
**取存器**
• 在设置属性值或者访问属性值的时候调用的函数
**抽象类**
• 1)提供其他类继承的基类,不能直接被实例化
• 2)抽象方法不能脱离抽象类使用
• 3)抽象方法不能有具体体现,只能在派生类中实现
• 4)抽象类和抽象方法是定义标准的
**类型接口**
• 1)使用接口可以强制一个类的定义必须包含某些内容
• 2)接口检测是使用这个接口定义的类创建的实例
**接口继承类**
• 1)接口可以继承一个类,继承该类后就会继承类成员,但是只继承成员和成员类现
• 2)当接口继承的这个类中包含private和protected两个修饰符的时候,这个接口只能被这个类或者他的子类实现
泛型
*我们在定义函数之前,使用`<>`符号定义了一个泛型变量 T,这个 T 在这次函数定义中就代表某一种类型,它可以是基础类型,也可以是联合类型等高级类型。
简单使用:· 泛型(Generics)是指在定义函数、接口或类的时候,不预先指定具体的类型,而在使用的时候再指定类型的一种特性**, 使用标识符号**<T>**
· <T>符号定义了一个泛型变量
· T在这次函数定义中就代表一种类型,他可以是基础类型,也可以是联合类型等高级类型
· 定义了泛型变量之后,你在函数中任何需要指定类型的地方使用T都代表这一种类型
泛型变量 :· 当我们使用泛型的时候,你必须在处理类型涉及到泛型的数据的时候,把这个数据当做任意类型来处理
· 这就意味着不是所有类型都能做的操作不能做,不是所有类型都能调用的方法不能调用
泛型函数类型:· 我们可以定义一个泛型函数类型
· 也可以使用接口的形式来定义泛型函数类型
· 还可以把接口泛型变量提升到接口最外层,这样接口中所有属性和方法都能使用这个泛型变量了
使用泛型约束限制泛型变量: · 泛型约束 : 当我们使用了泛型时,就意味着这个类型是任意类型,但是大多数情况下,我们的逻辑是对特定逻辑处理的
· 在泛型约束中使用类型参数 keyof是用来检查的类
类的修饰符:
· public : 共有属性方法修饰符,这是默认修饰符;
· private : 私有修饰符,它修饰的属性在类的定义外面无法访问。
· protected : 和private相似,区别在于他修饰的成员在继承该类的子类中可以访问。
· readonly : 只读修饰符
· abstract : 关键字修饰类定义,抽象类一般用来被其他类继承,而不是直接用它创建实例
类既是值,也是类型,当我们使用类创建一个实例的时候,这个实例的类型也就是这个创建这个实例的类。
TS中的类和ES6中的类的相同点和不同点 :
1. 都是采用extends语法进行继承
2. 在constructor中都需要首先使用super(xxx)调用父类构造函数,然后才能给this进行赋值
3. super作为方法时指向父类构造函数,而作为对象在普通方法中时指向父类的原型,在静态方法中指向父类
不同点:
1. TypeScript提供抽象类,抽象方法,和接口继承,具体使用请参考TypeScript官方文档
2. TypeScript可以对类中属性或方法使用访问限定符。
总结: 就是对封装和修饰符有了一定的区别,继承之类的和js是相同的
**类**
• 1)类其实就是继承
• 2)声明类的时候,需要对类的属性的数据类型进行约束
**类的继承**
• 1)es6继承:extends来继承,super来承接父辈的属性
• 2)类:和es6一样,只是添加了属性的数据类型
**类的修饰符**
• 1)public:公共的,类里面、子类、类外面都可以访问
• 2)protected:保护类型,类里面、子类可以访问,类外面不能
• 3)private:私有类型,类里面可以访问,其他不行
• 4)readonly:只读属性,只能读取不能修改
**静态属性**
• 使用static修饰静态属性,不能再实例上获取
**静态方法**
• 不能在实例上获取
**可选类属性**
• 类也可以使用 ?来标记表示为可选属性
**多态**
• 父类定义一个方法不去实现,让继承的子类去实现,每个子类有不同的表现
**取存器**
• 在设置属性值或者访问属性值的时候调用的函数
**抽象类**
• 1)提供其他类继承的基类,不能直接被实例化
• 2)抽象方法不能脱离抽象类使用
• 3)抽象方法不能有具体体现,只能在派生类中实现
• 4)抽象类和抽象方法是定义标准的
**类型接口**
• 1)使用接口可以强制一个类的定义必须包含某些内容
• 2)接口检测是使用这个接口定义的类创建的实例
**接口继承类**
• 1)接口可以继承一个类,继承该类后就会继承类成员,但是只继承成员和成员类型,不包括实现
• 2)当接口继承的这个类中包含private和protected两个修饰符的时候,这个接口只能被这个类或者他的子类实现
```
**day07**
**1.unkonw详解**
```
1. 任何类型的值都可以赋值给 unknown 类型
2. 如果没有类型断言或基于控制流的类型细化时 unknown 不可以赋值给其它类型,此时它只能赋值给 unknown 和 any 类型
3. 如果没有类型断言或基于控制流的类型细化,则不能在它上面进行任何操作
4. unknown 与任何其它类型组成的交叉类型,最后都等于其它类型
5. unknown 与任何其它类型组成的联合类型,都等于 unknown 类型,但只有any例外,unknown与any组成的联合类型等于any)
6. never 类型是 unknown 的子类型
7. keyof unknown 等于类型 never
8. 只能对 unknown 进行等或不等操作,不能进行其它操作
9. unknown 类型的值不能访问其属性、作为函数调用和作为类创建实例
10. 使用映射类型时如果遍历的是 unknown 类型,则不会映射任何属性
小节:
我们详细学习了 unknown 类型,它和 any 有相似的特点,就是制定一个类型是任意的,但是区别在于制定一个类型为 any 的话,可以在这个值上做任意操作,而 unknown 类型则不允许在没有类型断言或基于控制流的类型细化时对 unknown 类型的值做任何操作。
```
**2.装饰器**
**注意** 如果你要使用装饰器,需要在 tsconfig.json 的编译配置中开启`experimentalDecorators`,将它设为 true。
```
1.概念:
1)定义: 装饰器是一种新的声明,它能够作用于**类声明、方法、访问符、属性和参数**上
2)符号: @xxx(自定义的函数名称)
3)注意点: 要注意**装饰器要紧挨着要修饰的内容的前面**
2.装饰器工厂:
闭包的概念是: 内部函数可以返回外部的函数,内部可以调用外部的函数
装饰器工厂也是一个函数,它的返回值是一个函数,返回的函数作为装饰器的调用函数。如果使用装饰器工厂,那么在使用的时候,就要加上函数调用
3.装饰器组合:对于同一个目标,引用多个装饰器
1.这里要格外注意的是,多个装饰器的执行顺序:
装饰器工厂从上到下依次执行,但是只是用于返回函数但不调用函数
装饰器函数从下到上依次执行,也就是执行工厂函数返回的函数
(多个装饰器,会先执行装饰器工厂函数获取所有装饰器,然后再从后往前执行装饰器的逻辑。)
4.类装饰器 :在类声明之前声明,要记着装饰器要紧挨着要修饰的内容,类装饰器应用于类的声明。
类装饰器表达式会在运行时当做函数被调用,它由唯一一个参数,就是装饰的这个类。
5.方法装饰器:用来处理类中方法,它可以处理方法的属性描述符,可以处理方法定义。方法装饰器在运行时也是被当做函数调用
有三个参数:
1.装饰静态成员时是类的构造函数,装饰实例成员时是类的原型对象;
2.成员的名字;
3.成员的属性描述符。
属性描述符:对象可以设置属性,如果属性值是函数,那这个函数称为方法。每一个属性和方法在定义的时候,都伴随三个属性描述符`configurable`、`writable`和`enumerable`,分别用来描述这个属性的可配置性、可写性和可枚举性。这三个描述符,需要使用 ES5 才有的 Object.defineProperty 方法来设置
注意,当构建目标小于 ES5 的时候,方法装饰器的返回值会被忽略。
6. 访问器装饰器:我们之前讲过的 set 和 get 方法,一个在设置属性值的时候触发,一个在获取属性值的时候触发。
首先要注意一点的是,TS 不允许同时装饰一个成员的 get 和 set 访问器,只需要这个成员 get/set 访问器中定义在前面的一个即可。
有三个参数:
1.装饰静态成员时是类的构造函数,装饰实例成员时是类的原型对象;
2.成员的名字;
3.成员的属性描述符。
7. 属性装饰器:声明在属性声明之前,属性装饰器没法操作属性的属性描述符,它只能用来判断某各类中是否声明了某个名字的属性。
有两个参数:
1.装饰静态成员时是类的构造函数,装饰实例成员时是类的原型对象;
2.成员的名字;
8. 参数装饰器:
有三个参数:参数装饰器的返回值会被忽略
1.装饰静态成员时是类的构造函数,装饰实例成员时是类的原型对象
2.成员的名字
3.参数在函数参数列表中的索引
小节:
本小节我们全面学习了装饰器的相关内容,虽然装饰器在ECAMAScript标准的议程中还没有最终确定,但是TypeScript的装饰器却已经被很多人接收,很多库和插件使用装饰器来处理一些值。本小节我们学习了装饰器的定义,以及使用装饰器工厂函数来实现可传参使用装饰器,这里我们着重强调了当一个地方添加了多个装饰器工厂函数和装饰器时的执行顺序,装饰器工厂函数是从上到下执行,装饰器是从下到上执行。我们还分别学习了:类装饰器、方法装饰器、访问器装饰器、属性装饰器和参数装饰器,它们分别处理对应的值。
```
**3.声明的合并**
```
1.声明合并是指 TypeScript 编译器会将名字相同的多个声明合并为一个声明,合并后的声明同时拥有多个声明的特性。我们知道在 JavaScrip 中,使用var关键字定义变量时,定义相同名字的变量,后面的会覆盖前面的值。使用let 定义变量和使用 const 定义常量时,不允许名字重复。在 TypeScript 中,接口、命名空间是可以多次声明的,最后 TypeScript 会将多个同名声明合并为一个。
2.Interface声明可以被覆盖
3.type只能声明一次,并不能被覆盖
4.总结:TypeScript的所有声明概括起来,会创建这三种实体之一:**命名空间、类型**和**值**:
1.命名空间的创建实际是创建一个对象,对象的属性是在命名空间里export导出的内容;
2.类型的声明是创建一个类型并赋给一个名字;
3.值的声明就是创建一个在JavaScript中可以使用的值。
```
**4.tsconfig的配置**
```
主要讲 tsconfig.json 文件的可配项以及功能:
tsconfig.json 是放在项目根目录,用来配置一些编译选项等。当我们使用 tsc 命令编译项目,且没有指定输入文件时,编译器就会去查找 tsconfig.json 文件。如果在当前目录没找到,就会逐级向父文件夹查找。我们也可以通过在 tsc 命令中加上–project 参数,来指定一个包含 tsconfig.json 文件的目录。如果命令行上指定了输入文件时,tsconfig.json 的配置会被忽略。
1.作用,以及可配置的值:
1.compileOnSave:
compileOnSave 的值是 true 或 false。如果设为 true,在我们编辑了项目中文件保存的时候,编辑器会根据 tsconfig.json 的配置重新生成文件,不过这个要编辑器支持。
2.files
files 可以配置一个数组列表,里面包含指定文件的相对或绝对路径。编译器在编译的时候只会编译包含在 files 中列出的文件。如果不指定,则取决于有没有设置 include 选项;如果没有 include 选项,则默认会编译根目录以及所有子目录中的文件。这里列出的路径必须是指定文件,而不是某个文件夹,而且不能使用`*`、`?`、`**/`等通配符。
3.include
include 也可以指定要编译的路径列表,但和 files 的区别在于,这里的路径可以是文件夹,也可以是文件,可以使用相对和绝对路径,而且可以使用通配符。比如`"./src"`即表示要编译 src 文件夹下的所有文件以及子文件夹的文件。
4.exclude
exclude 表示要排除的、不编译的文件,它也可以指定一个列表,规则和 include 一样,可以是文件可以是文件夹,可以是相对路径或绝对路径,可以使用通配符。
5.extends
extends 可以通过指定一个其它的 tsconfig.json 文件路径,来继承这个配置文件里的配置,继承来的文件配置会覆盖当前文件定义的配置。TS 在 3.2 版本开始,支持继承一个来自 Node.js 包的 tsconfig.json 配置文件。
6.compilerOptions
compilerOptions 是重点,它用来设置编译选项。因为它包含很多的可配置项
所有可配项:
1.基本的配置:
1.target 用于指定编译之后的版本目标,可选值有:`ES3(默认值)`、`ES5`、`ES2015`、`ES2016`、`ES2017`、`ESNEXT`。如果不配置 target 项,默认是讲代码转译为 ES3 的版本,如果设为 ESNEXT,则为最新 ES 规范版本。
2.module 用来指定要使用的模块标准,可选值有`commonjs`、`amd`、`system`、`umd`、`es2015(或写 es6)`。如果不设置 module 选项,则如果 target 设为 ES6,那么 module 默认值为 ES6,否则是 commonjs。
3.lib 用于指定要包含在编译中的库文件。如果你要使用一些 ES6 的新语法,你需要引入 ES6 这个库,或者也可以写 ES2015。如果没有指定 lib 配置,默认会加载一些库,而加载什么库是受 target 影响的。如果 target 为 ES5,默认包含的库有`DOM`、`ES5`和`ScriptHost`;如果 target 是 ES6,默认引入的库有`DOM`、`ES6`、`DOM.Iterable`和`ScriptHost`。
4.allowJs 设置的值为 true 或 false,用来指定是否允许编译 JS 文件,默认是 false,即不编译 JS 文件。
5.checkJs 的值为 true 或 false,用来指定是否检查和报告 JS 文件中的错误,默认是 false。
6.declaration 的值为 true 或 false,用来指定是否在编译的时候生成响应的".d.ts"声明文件。如果设为 true,编译每个 ts 文件之后会生成一个 js 文件和一个声明文件。但是 declaration 和 allowJs 不能同时设为 true。
7.sourceMap 的值为 true 或 false,用来指定编译时是否生成.map 文件。
8.outFile 用于指定将输出文件合并为一个文件,它的值为一个文件路径名,比如设置为`"./dist/main.js"`,则输出的文件为一个 main.js 文件。但是要注意,只有设置 module 的值为 amd 和 system 模块时才支持这个配置。
9.outDir 用来指定输出文件夹,值为一个文件夹路径字符串,输出的文件都将放置在这个文件夹。
10.用来指定编译文件的根目录,编译器会在根目录查找入口文件,如果编译器发现 1 以 rootDir 的值作为根目录查找入口文件并不会把所有文件加载进去的话会报错,但是不会停止编译。
11.removeComments 值为 true 或 false,用于指定是否将编译后的文件中的注释删掉,设为 true 的话即删掉注释,默认为 false。
12.importHelpers 的值为 true 或 false,指定是否引入 tslib 里的辅助工具函数,默认 Wie。
13.isolatedModules 的值为 true 或 false,指定是否将每个文件作为单独的模块,默认为 true,它不可以和 declaration 同时设定。
2.严格类型检查相关的,开启了这些检查如果有错会报错:
1.noImplicitAny 的值为 true 或 false,如果我们没有为一些值设置明确的类型,编译器会默认这个值为 any 类型,如果将 noImplicitAny 设为 true,则如果没有设置明确的类型会报错,默认值为 false。
2.alwaysStrict 的值为 true 或 false,指定始终以严格模式检查每个模块,并且在编译之后的 JS 文件中加入"use strict"字符串,用来告诉浏览器该 JS 为严格模式。
3.strictNullChecks 的值为 true 或 false,当设为 true 时,null 和 undefined 值不能赋值给非这两种类型的值,别的类型的值也不能赋给它们。 除了 any 类型,还有个例外就是 undefined 可以赋值给 void 类型。
4.strictFunctionTypes 的值为 true 或 false,用来指定是否使用函数参数双向协变检查。如果开启了 strictFunctionTypes,这个赋值就会报错,默认为 false
5.strictPropertyInitialization 的值为 true 或 false,设为 true 后会检查类的非 undefined 属性是否已经在构造函数里初始化,如果要开启这项,需要同时开启 strictNullChecks,默认为 false。
6.strictBindCallApply 的值为 true 或 false,设为 true 后会对 bind、call 和 apply 绑定方法参数的检测是严格检测的
7.strict 的值为 true 或 false,用于指定是否启动所有类型检查,如果设为 true 则会同时开启前面这几个严格类型检查,默认为 false
3.为额外的一些检查,开启了这些检查如果有错会提示不会报错:
1.noUnusedLocals 的值为 true 或 false,用于检查是否有定义了但是没有使用的变量,对于这一点的检测,使用 ESLint 可以在你书写代码的时候做提示,你可以配合使用。它的默认值为 false。
2.noUnusedParameters 的值为 true 或 false,用于检查是否有在函数体中没有使用的参数,这个也可以配合 ESLint 来做检查,它默认是 false。
3.noImplicitReturns 的值为 true 或 false,用于检查函数是否有返回值,设为 true 后,如果函数没有返回值则会提示,默认为 false。
4.noFallthroughCasesInSwitch 的值为 true 或 false,用于检查 switch 中是否有 case 没有使用 break 跳出 switch,默认为 false。
4.模块解析相关的:
1.moduleResolution 用于选择模块解析策略,有"node"和"classic"两种类型,我们在讲模块解析的时候已经讲过了。
2.baseUrl 用于设置解析非相对模块名称的基本目录,这个我们在讲《模块和命名空间》的“模块解析配置项”一节时已经讲过了,相对模块不会受 baseUrl 的影响。
3.paths 用于设置模块名到基于 baseUrl 的路径映射
4.rootDirs 可以指定一个路径列表,在构建时编译器会将这个路径列表中的路径内容都放到一个文件夹中,我们在前面也学习了
5.typeRoots 用来指定声明文件或文件夹的路径列表,如果指定了此项,则只有在这里列出的声明文件才会被加载。
6.types 用来指定需要包含的模块,只有在这里列出的模块声明文件才会被加载进来。
7.allowSyntheticDefaultImports 的值为 true 或 false,用来指定允许从没有默认导出的模块中默认导入。
5. source map 的一些配置项:
1.sourceRoot 用于指定调试器应该找到 TypeScript 文件而不是源文件位置,这个值会被写进.map 文件里。
2.mapRoot 用于指定调试器找到映射文件而非生成文件的位置,指定 map 文件的根路径,该选项会影响.map 文件中的 sources 属性。
3.inlineSourceMap 值为 true 或 false,指定是否将 map 文件的内容和 js 文件编译在同一个 js 文件中。如果设为 true,则 map 的内容会以`//# sourceMappingURL=`然后接 base64 字符串的形式插入在 js 文件底部。
4.inlineSources 的值是 true 或 false,用于指定是否进一步将.ts 文件的内容也包含到输出文件中。
6.其他的配置项:
1.experimentalDecorators 的值是 true 或 false,用于指定是否启用实验性的装饰器特性,我们在讲装饰器的时候已经学习过了。
2.emitDecoratorMetadata 的值为 true 或 false,用于指定是否为装饰器提供元数据支持。关于元数据,也是 ES6 的新标准,可以通过 Reflect 提供的静态方法获取元数据,如果需要使用 Reflect 的一些方法,需要引入 ES2015.Reflect 这个库。
小节:我们逐条看了tsconfig.json文件里可以配置的项目,随着后面TypeScript的升级,可能配置项会比这里多,你可以参考官方文档的升级日志来查看更新。
我们学了六个顶级配置项:compileOnSave、files、include、exclude、extends和compilerOptions,其中我们最常用的是compilerOptions,用来配置编译选项。有一些参数是只能在tsconfig.json文件里配置的,而有一些则既可以在tsconfig.json文件配置,也可以在tsc命令行中指定