对应任何类型
T
,keyof T
的结果为该类型上所有公有属性key的联合;
只有 readonly 和 public 属性值可以被 keyof 捕捉到
interface Eg1 {
name: string,
readonly age: number,
}
// T1的类型实则是name | age
type T1 = keyof Eg1
class Eg2 {
private name: string;
public readonly age: number;
protected home: string;
}
// T2实则被约束为 age
// 而name和home不是公有属性,所以不能被keyof获取到
type T2 = keyof Eg2
T[keyof T]
的方式,可以获取到T
所有key
的类型组成的联合类型;T[keyof K]
的方式,获取到的是T
中的key
且同时存在于K
时的类型组成的联合类型; 注意:如果[]
中的key有不存在T中的,则是any;因为ts也不知道该key最终是什么类型,所以是any;且也会报错。
interface Eg1 {
name: string,
readonly age: number,
}
type V1 = Eg1['name'] // string
type V2 = Eg1['name' | 'age'] // string | number
type V2 = Eg1['name' | 'age2222'] // any
type V3 = Eg1[keyof Eg1] // string | number
-
表示继承/拓展的含义 : class
-
表示约束的含义
// redux 里 dispatch 一个 action,必须包含 type属性: interface Dispatch<T extends { type: string }> { (action: T): T }
-
表示分配的含义
type Equal<X, Y> = X extends Y ? true : false;
type Num = Equal<1, 1>; // true
type Str = Equal<'a', 'a'>; // true
type Boo = Equal<true, false>; // false
type isNum<T> = T extends number ? number : string
type Num = isNum<1> // number;
type Str = isNum<'1'> // string;
type TypeName<T> =
T extends string ? "string" :
T extends number ? "number" :
T extends boolean ? "boolean" :
T extends undefined ? "undefined" :
T extends Function ? "function" :
"object";
type T0 = TypeName<string>; // "string"
type T1 = TypeName<"a">; // "string"
type T2 = TypeName<true>; // "boolean"
type T3 = TypeName<() => void>; // "function"
type T4 = TypeName<string[]>; // "object"
其中联合类型 A 的全部子类型,在联合类型 B 中存在,则条件满足。 若是咱们把返回值替换为其余的类型定义,就能根据判断,得出想要的类型。c
type A = 'x'| 4;
type B = 'x' | 'y' | 4;
type Y = A extends B ? true : false; // true
先进行 x extends "x" 得到 "a" | "b" , 再执行 y extends "x" 得到 'y' , 最后结果即 "a" | "b" | 'y'
type Other = "a" | "b";
type Merge<T> = T extends "x" ? Other : T; // T 等于除匹配类型的额外全部类型(官方叫候选类型)
type Values = Merge<"x" | "y">;// 获得 type Values = "a" | "b" | 'y';
由上面可以得到 Diff,
type Diff<T, U> = T extends U ? never : T; // 找出T的差集
type Filter<T, U> = T extends U ? never : T; // 找出交集
type Values = Filter<"x" | "y" | "z", "x">; // 获得 type Values = "y" | "z"
在extends语句中,还支持
infer
关键字,能够推断一个类型变量,高效的对类型进行模式匹配。可是,这个类型变量只能在true的分支中使用,也就是下面的 R 只能在 ?左边使用;
type ReturnType<T> = T extends (...args: any[]) => infer R ? R : any;
若是
T
是某个待推断类型的数组,则返回推断的类型 R,不然返回T
// 当?左边为 true 时就返回 数组中的类型, 否则返回 T
type ExtractArrayItemType<T> = T extends (infer R)[] ? R : T;
// 条件判断都为 false,返回 T
type T1 = ExtractArrayItemType<string>; // string
type T2 = ExtractArrayItemType<() => number>; // () => number
type T4 = ExtractArrayItemType<{ a: string }>; // { a: string }
// 条件判断为 true,返回 U
type T3 = ExtractArrayItemType<Date[]>; // Date
1.1 取出数组或元组中第一个的类型
// 元组第一项的类型,可用在 Hooks 风格的 React 组件中
type Head<T> = T extends [infer H, ...any[]] ? H : never;
// 解读: 若是泛型变量T是 () => infer R的`子集`,那么返回 经过infer获取到的函数返回值,不然返回boolean类型
// ()=>infer R 获取的是函数返回值
type Func<T> = T extends () => infer R ? R : boolean;
let func1: Func<number>; // boolean
let func2: Func<''>; // boolean
let func3: Func<() => Promise<number>>; // Promise<number>
推断函数返回值类型
若是
T
是一个函数,则返回函数的返回值,不然返回any
type ReturnType<T> = T extends (...args: any[]) => infer R ? R : any;
type func = () => number;
type variable = string;
type funcReturnType = ReturnType<func>; // funcReturnType 类型为 number
type varReturnType = ReturnType<variable>; // varReturnType 类型为 string
同一个类型变量在推断的值有多种状况的时候会推断为联合类型
// 当a、b为不一样类型的时候,返回不一样类型的联合类型
type Obj<T> = T extends {a: infer VType, b: infer VType} ? VType : number;
let obj1: Obj<string>; // number
let obj2: Obj<true>; // number
let obj3: Obj<{a: number, b: number}>; // number
let obj4: Obj<{a: number, b: () => void}>; // number | () => void
// 同一个值类型可能会有多样
type ElementOf<T> = T extends (infer R)[] ? R : never;
// 元组转联合类型
type TTuple = [string, number];
type Union = ElementOf<TTuple>; // Union 类型为 string | number
// 方式2
type Res = TTuple[number]; // string | number
获取
Promise<xxx>
类型中的xxx
类型
type Response = Promise<number[]>;
type Unpacked<T> = T extends Promise<infer R> ? R : T;
type resType = Unpacked<Response>; // resType 类型为number[]
返回 a, b 的联合类型
type Foo<T> = T extends { a: infer U; b: infer U } ? U : never;
type T10 = Foo<{ a: string; b: string }>; // T10类型为 string
type T11 = Foo<{ a: string; b: number }>; // T11类型为 string | number
type ParamType<T> = T extends (...param: [infer P, ...infer R]) => any ? P : never;
type Fn = (name:number, age: number,address: string)=>any
type AA = ParamType<Fn> // number
interface User {
name: string;
age: number;
}
type Func = (user: User) => void
type Param = ParamType<Func>; // Param = User
type BB = ParamType<string>; // string
一个构造函数可使用
new
来实例化,所以它的类型一般表示以下,将 infer R 移动到返回值位置就是获取返回值,移动到参数位置就是获取参数
type Constructor = new (...args: any[]) => any;
获取返回值类型,即实例类型
// 获取参数类型,得到数组
type ConstructorParameters<T extends new(...args:any[])=>any> = T extends new(...args: infer R) => any ? R: never
// 获取实例类型
type InstanceType<T extends new(...args:any[])=>any> = T extends new(...args:any[]) => infer R ? R:never
class TestClass {
constructor( public name: string, public string: number ) {}
}
type Params = ConstructorParameters<typeof TestClass>; // [string, numbder]
type Instance = InstanceType<typeof TestClass>; // TestClass
-
如下实现一个 promisify, 接受一个值,若是它已是
Promise
了,就直接返回;若是不是,就把它包在一个Promise
中返回;function promisify<T> (input: T): T extends Promise ? T : Promise<T> { if (input instanceOf Promise) { return input; } return Promise.resolve(input); }
-
要把
Promise
中的值包在一个 { value: T } 的结构中返回,需要确定其返回值类型;function promisify2<T> (input: T) { if (input instanceof Promise) { return input.then(value => ({ value })); } return Promise.resolve({ value: input }); }
-
首先,如果 value 是Promise 就返回 T 类型, 否则就返回 value 类型
type Unpromise<T> = T extends Promise<infer U> ? U : T; type Test1 = Unpromise<number>; // number type Test2 = Unpromise<Promise<string>>; // string
-
最后实现如下:
type Unpromise<T> = T extends Promise<U> ? U : T; // 明确返回值类型 type Container<T> = Promise<{ value: T }>; // 将返回值类型进行包装,最后得到的都是一个普通含有 value 属性的对象 function promisify2<T>(input: T): Container<Unpromise<T>> { if (input instanceof Promise) { return input.then(value => ({ value })); } return Promise.resolve({ value: input }); }
-