知识点摘要
本节课主要关键词为: 自动类型推断 / 类型断言 / 类型别名(type) / 映射类型(Pick/Record等...) / 条件类型(extends) / 类型推断(infer)
自动类型推断(不用你标类型了,ts自己猜)
第二课我们讲了那么多基础类型, 大家现在写ts的时候一定会在每个变量后面都加上类型吧? 但是?
现在告诉大家有些情况下你不需要标注类型, ts可以根据你写的代码来自动推断出类型:
赋值字面量给变量
let n = 1;
自动阅读if条件判断
let n: number|null = 0.5 < Math.random() ? 1:null;
if(null !== n){
n+=3
浏览器自带api
document.ontouchstart = ev=>{
typeof
typeof 就是js中的typeof , ts会根据你代码中出现的typeof 来自动推断类型:
let n:number|string = 0.5 < Math.random()? 1:'1';
注意: 在ts文档中, 该部分的知识点叫做typeof类型保护, 和其他类型推断的内容是分开的, 被写在高级类型/类型保护章节中.
instanceof
ts会根据你代码中出现的instanceof 来自动推断类型:
let obj = 0.5 < Math.random() ? new String(1) : new Array(1);
if(obj instanceof String){
注意: 在ts文档中, 该部分的知识点叫做instanceof类型保护, 和其他类型推断的内容是分开的, 被写在高级类型/类型保护章节中.
类型断言(你告诉ts是什么类型, 他都信)
有些情况下系统没办法自动推断出正确的类型, 就需要我们标记下, 断言有2种语法, 一种是通过"<>", 一种通过"as", 举例说明:
let obj = 0.5 < Math.random() ? 1 : [1];
类型别名(type)
类型别名可以表示很多接口表示不了的类型, 比如字面量类型(常用来校验取值范围):
type A = 'top'|'right'|'bottom'|'left';
更多组合:
interface A1{
a:number;
}
type B = A1 | {b:string};
type C = A1 & {b:string};
索引类型(keyof)
js中的Object.keys 大家肯定都用过, 获取对象的键值, ts中的keyof 和他类似, 可以用来获取对象类型的键值:
type A = keyof {a:1,b:'123'}
可以获得键值, 也可以获取对象类型的值的类型:
type C = A['a']
映射类型(Readonly, Pick, Record等...)
映射类型比较像修改类型的工具函数, 比如Readonly 可以把每个属性都变成只读:
type A = {a:number, b:string}
type A1 = Readonly<A>
打开node_modules/typescript/lib文件夹可以找到lib.es5.d.ts , 在这我们能找到Readonly 的定义:
type Readonly<T> = {
readonly [P in keyof T]: T[P];
};
其实不是很复杂, 看了本节课前面前面的内容, 这个很好理解是吧:
- 定义一个支持泛型的类型别名, 传入类型参数
T .
- 通过
keyof 获取T 上的键值集合.
- 用
in 表示循环keyof 获取的键值.
- 添加
readonly 标记.
Partial<T>, 让属性都变成可选的
type A = {a:number, b:string}
type A1 = Partial<A>
Required<T>, 让属性都变成必选
type A = {a?:number, b?:string}
type A1 = Required<A>
Pick<T,K>, 只保留自己选择的属性, U代表属性集合
type A = {a:number, b:string}
type A1 = Pick<A, 'a'>
Omit<T,K> 实现排除已选的属性
type A = {a:number, b:string}
type A1 = Omit<A, 'a'>
Record<K,T>, 创建一个类型,T代表键值的类型, U代表值的类型
type A1 = Record<string, string>
Exclude<T,U>, 过滤T中和U相同(或兼容)的类型
type A = {a:number, b:string}
type A1 = Exclude<number|string, string|number[]>
Extract<T,U>, 提取T中和U相同(或兼容)的类型
type A = {a:number, b:string}
type A1 = Extract<number|string, string|number[]>
NonNullable<T>, 剔除T中的undefined和null
type A1 = NonNullable<number|string|null|undefined>
ReturnType<T>, 获取T的返回值的类型
type A1= ReturnType<()=>number>
InstanceType<T>, 返回T的实例类型
ts中类有2种类型, 静态部分的类型和实例的类型, 所以T 如果是构造函数类型, 那么InstanceType 可以返回他的实例类型:
interface A{
a:HTMLElement;
}
interface AConstructor{
new():A;
}
function create (AClass:AConstructor):InstanceType<AConstructor>{
return new AClass();
}
Parameters<T> 获取函数参数类型
返回类型为元祖, 元素顺序同参数顺序.
interface A{
(a:number, b:string):string[];
}
type A1 = Parameters<A>
ConstructorParameters<T> 获取构造函数的参数类型
和Parameters 类似, 只是T 这里是构造函数类型.
interface AConstructor{
new(a:number):string[];
}
type A1 = ConstructorParameters<AConstructor>
extends(条件类型)
T extends U ? X : Y
用来表示类型是不确定的, 如果U 的类型可以表示T , 那么返回X , 否则Y . 举几个例子:
type A = string extends '123' ? string :'123'
明显string 的范围更大, '123' 可以被string 表示, 反之不可.
infer(类型推断)
单词本身的意思是"推断", 实际表示在extends 条件语句中声明待推断的类型变量. 我们上面介绍的映射类型中就有很多都是ts在lib.d.ts 中实现的, 比如Parameters :
type Parameters<T extends (...args: any) => any> = T extends (...args: infer P) => any ? P : never;
上面声明一个P 用来表示...args 可能的类型, 如果(...args: infer P) 可以表示 T , 那么返回...args 对应的类型, 也就是函数的参数类型, 反之返回never .
注意: 开始的T extends (...args: any) => any 用来校验输入的T 是否是函数, 如果不是ts会报错, 如果直接替换成T 不会有报错, 会一直返回never .
应用infer
接下来我们利用infer 来实现"删除元祖类型中第一个元素", 这常用于简化函数参数
export type Tail<Tuple extends any[]> = ((...args: Tuple) => void) extends ((a: any, ...args: infer T) => void) ? T : never;
|
请发表评论