typescript 高级用法
运算符
- 非空断言运算符 !
!放在变量名或函数名后,用来强调该变量名或函数名非null|undefined。
这个符号特别适用于我们已经明确知道不会返回空值的场景。
function onClick(callback?: () => void) {
callback!(); // 参数是可选入参,加了这个感叹号!之后,TS编译不报错
}
- 可选链运算符 ?.
判断左侧的表达式是否是 null | undefined,如果是则会停止表达式运行,可以减少我们大量的&&运算。
a?.b
// 相当于
a === null || a === void 0 ? void 0 : a.b;
- 空值合并运算符 ??
??在左侧表达式结果为 null 或者 undefined 时,才会返回右侧表达式 .
let b = a ?? 10
// 相当于
let b = a !== null && a !== void 0 ? a : 10;
操作符
- keyof
获取一个类型所有键值,返回一个联合类型
type Person = {
name: string;
age: number;
}
type PersonKey = keyof Person; // PersonKey得到的类型为 'name' | 'age'
keyof 的一个典型用途是限制访问对象的 key 合法化,因为 any 做索引是不被接受的。
function getValue (p: Person, k: keyof Person) {
return p[k]; // 如果k不如此定义,则无法以p[k]的代码格式通过编译
}
- typeof
获取一个对象/实例的类型。
const me: Person = { name: 'gzx', age: 16 };
type P = typeof me; // { name: string, age: number | undefined }
const you: typeof me = { name: 'mabaoguo', age: 69 } // 可以通过编译
typeof 可以和 keyof 一起使用(因为 typeof 是返回一个类型)
type PersonKey = keyof typeof me; // 'name' | 'age'
- 遍历属性 in
in 只能用在类型的定义中,可以对枚举类型进行遍历。
// 这个类型可以将任何类型的键值转化成number类型
type TypeToNumber<T> = {
[key in keyof T]: number
}
const obj: TypeToNumber<Person> = { name: 10, age: 10 }
泛型
泛型推断infer
type Foo<T> = T extends {t: infer Test} ? Test : string
{t: infer Test} 是一个类型对象,包含属性t,t的value类型通过infer进行推断后会赋值给Test类型。
举例:
type One = Foo<number> // string,因为number不是一个包含t的对象类型
type Two = Foo<{t: boolean}> // boolean,因为泛型参数匹配上了,使用了infer对应的type
type Three = Foo<{a: number, t: () => void}> // () => void,泛型定义是参数的子集,同样适配
type ParamType<T> = T extends (param: infer P) => any ? P : T;
infer P 表示待推断的函数参数。如果T能赋值给(param: infer P) => any,则结果为参数P类型,否则返回T。
举例:
interface User {
name: string;
age: number;
}
type Func = (user: User) => void
let type1 = ParamType<Func> // User
let type2 = ParamType<string> // string
提取函数类型的返回值类型:
type ReturnType<T> = T extends (...args: any[]) => infer P ? P : any;
ReturnType
举例:
type Func = () => User;
type Test = ReturnType<Func>; // Test = User
泛型工具
- Partial
将泛型中的全部属性变成可选
type Partial<T> = {
[P in keyof T]?: T[P]
}
举例:
type Animal = {
name: string,
category: string,
age: number,
eat: () => number
}
type PartOfAnimal = Partial<Animal>
const ww: PartOfAnimal = { name: 'ww' }; // 属性全部可选后,可以只赋值部分属性了
- Record<K, T>
将K中左右的属性值都转化成T类型
type Record<K extends keyof any, T> {
[P in K]: T
}
keyof any对应的类型为number | string | symbol,也就是可以做对象键(专业说法叫索引 index)的类型集合
举例:
const obj: Record<string, string> = { 'name': 'zhangsan', 'tag': '打工人' }
- Pick<T, K>
将类型T中的属性K提取出来,生成新的键值对。
type Pick<T, K extends keyof T> = {
[P in K]: T[P]
}
举例:
type Animal = {
name: string,
category: string,
age: number,
eat: () => number
}
const bird: Pick<Animal, "name" | "age"> = { name: 'bird', age: 1 }
- Exclude<T, U>
去除T类型中和U类型有交集的部分,返回剩余部分
type Exclude<T, U> = T extends U ? never : T
举例:
type T1 = Exclude<"a" | "b" | "c", "a" | "b">; // "c"
- Omit<T, K>
Construct a type with the properties of T except for those in type K.
type Omit <T, K extends keyof any> = Pick<T, Exclude<keyof T, K>>
第一步先从 T 的 key 中去掉与 K 重叠的 key,接着使用 Pick 把 T 类型和剩余的 key 组合起来即可。
举例:
type Animal = {
name: string,
category: string,
age: number,
eat: () => number
}
const OmitAnimal:Omit<Animal, 'name'|'age'> = { category: 'lion', eat: () => { console.log('eat') } }
- ReturnType
type ReturnType<T extends (...args: any) => any> = T extends (...args: any) => infer R ? R : any;
// 可以简化为:
type ReturnType<T> = T extends (...args: any) => inter R ? R : any
ReturnType
- Required
将类型 T 中所有的属性变为必选项
type Required<T> = {
[P in keyof T]-?: T[P];
};