辅助工具类型
- 对于交叉类型的结构,Flatten 能够将它展平为单层的对象结构
type Flatten<T> = { [K in keyof T]: T[K] };
属性修饰类型工具
- 深度可选参数
type DeepPartial<T extends object> = {
[K in keyof T]?: T[K] extends object ? DeepPartial<T[K]> : T[K];
};
- 深度必选参数
type DeepRequired<T extends object> = {
[K in keyof T]-?: T[K] extends object ? DeepRequired<T[K]> : T[K];
};
- 深度只读参数
// 也可以记作 DeepImmutable
type DeepReadonly<T extends object> = {
readonly [K in keyof T]: T[K] extends object ? DeepReadonly<T[K]> : T[K];
};
- 深度可变参数
type DeepMutable<T extends object> = {
-readonly [K in keyof T]: T[K] extends object ? DeepMutable<T[K]> : T[K];
};
- 从联合类型剔除
null | undefined
- 在开启
--strictNullChecks
下才能正常工作。
- 在开启
type NonNullable<T> = T extends null | undefined ? never : T;
type DeepNonNullable<T extends object> = {
[K in keyof T]: T[K] extends object
? DeepNonNullable<T[K]>
: NonNullable<T[K]>;
};
基于部分属性修饰的类型工具
- 拆分对象结构,那不就是内置工具类型一节中讲到的结构工具类型,即 Pick 与 Omit?
- 三个属性的对象全部变为可选,那不就是属性修饰?岂不是可以直接用上面刚学到的递归属性修饰?
- 组合两个对象类型,也就意味着得到一个同时符合这两个对象类型的新结构,那不就是交叉类型?
- 将一个对象的部分属性标记为可选
/**
* T: 需要处理的对象类型
* K: 需要标记为可选的属性, 必须为 T 内部的属性, 对象属性组成的字面量联合类型
*/
type MarkPropsAsOptional<
T extends object,
K extends keyof T = keyof T
> = Flatten<Partial<Pick<T, K>> & Omit<T, K>>;
type MarkPropsAsOptionalStruct = MarkPropsAsOptional<
{
foo: string;
bar: number;
baz: boolean;
},
"bar"
>;
- 将一个对象的部分属性标记为必须
type MarkPropsAsRequired<
T extends object,
K extends keyof T = keyof T
> = Flatten<Omit<T, K> & Required<Pick<T, K>>>;
- 将一个对象的部分属性标记为只读
type MarkPropsAsReadonly<
T extends object,
K extends keyof T = keyof T
> = Flatten<Omit<T, K> & Readonly<Pick<T, K>>>;
- 将一个对象的部分属性不只读(可变)
type MarkPropsAsMutable<
T extends object,
K extends keyof T = keyof T
> = Flatten<Omit<T, K> & Mutable<Pick<T, K>>>;
- 讲一个对象的部分属性剔除
null | undefined
type MarkPropsAsNonNullable<
T extends object,
K extends keyof T = keyof T
> = Flatten<Omit<T, K> & NonNullable<Pick<T, K>>>;
结构工具
- 基于期望的类型去拿到所有此类型的属性名, Pick 出所有函数类型的值
type FuncStruct = (...args: any[]) => any;
type FunctionKeys<T extends object> = {
[K in keyof T]: T[K] extends FuncStruct ? K : never;
}[keyof T];
// 对上面的解释
type Tmp<T extends object> = {
[K in keyof T]: T[K] extends FuncStruct ? K : never;
};
type Res = Tmp<{
foo: () => void;
bar: () => number;
baz: number;
}>;
type ResEqual = {
foo: 'foo';
bar: 'bar';
baz: never;
};
type WhatWeWillGet = Res[keyof Res]; // 'foo' | 'bar'
type WhatWillWeGetEqual1 = Res["foo" | "bar" | "baz"];
type WhatWillWeGetEqual2 = Res["foo"] | Res["bar"] | Res["baz"];
type WhatWillWeGetEqual3 = "foo" | "bar" | never;
- 基于键值类型查找属性, 将预期类型也作为泛型参数
// 我们预期查找的类型, 第二个参数
type ExpectedPropKeys<T extends object, valueType> = {
[Key in keyof T]-?: T[Key] extends valueType ? Key : never;
}[keyof T];
type PickByValueType<T extends object, valueType> = Pick<
T,
ExpectedPropKeys<T, valueType>
>;
// {
// foo: string;
// }
type PickResult1 = PickByValueType<{ foo: string; bar: number }, string>;
// {
// foo: string;
// bar: number;
// }
type PickResult2 = PickByValueType<
{ foo: string; bar: number; baz: boolean },
string | number
>;
// OmitByValueType 也是类似的,我们只需要一个和 ExpectedPropKeys 作用相反的工具类型即可,比如来个 FilteredPropKeys,只需要调换条件类型语句结果的两端
type FilteredPropKeys<T extends object, ValueType> = {
[Key in keyof T]-?: T[Key] extends ValueType ? never : Key;
}[keyof T];
type OmitByValueType<T extends object, ValueType> = Pick<
T,
FilteredPropKeys<T, ValueType>
>;
type OmitRes1 = OmitByValueType<{ foo: string; bar: number }, string>;
type OmitRes2 = OmitByValueType<
{ foo: string; bar: number; baz: boolean },
string | number
>;
集合工具
// 一维
// 并集
type Concurrence<A, B> = A | B
// 交集
type Intersection<A, B> = A extends B ? A : never
// 差集
type Difference<A, B> = A extends B ? never : A
// 补集
type Complement<A, B extends A> = Difference<A, B>
- 属性名并集
// 实现对象属性名的版本
type PlainObjectType = Record<string, any>;
// 属性名并集
type ObjectKeysConcurrence<
T extends PlainObjectType,
U extends PlainObjectType
> = keyof T | keyof U;
- 属性名交集
// 属性名交集
type ObjectKeysIntersection<
T extends PlainObjectType,
U extends PlainObjectType
> = Intersection<keyof T, keyof U>;
- 属性名差集
// 属性名差集
export type ObjectKeysDifference<
T extends PlainObjectType,
U extends PlainObjectType
> = Difference<keyof T, keyof U>;
- 属性名补集
// 属性名补集
export type ObjectKeysComplement<
T extends U,
U extends PlainObjectType
> = Complement<keyof T, keyof U>;
- 提取首个参数类型
type FunctionType = (...args: any) => any;
type FirstParameter<T extends FunctionType> = T extends (
arg: infer P,
...args: any
) => any
? P
: never;
- 提取最后一个参数
type FunctionType = (...args: any) => any;
type LastParameter<T extends FunctionType> = T extends (arg: infer P) => any
? P
: T extends (...args: infer R) => any
? R extends [...any, infer Q]
? Q
: never
: never;
type FuncFoo = (arg: number) => void;
type FuncBar = (...args: string[]) => void;
type FuncBaz = (arg1: string, arg2: boolean) => void;
type FooLastParameter = LastParameter<FuncFoo>; // number
type BarLastParameter = LastParameter<FuncBar>; // string
type BazLastParameter = LastParameter<FuncBaz>; // boolean
- 提取 Promise 内部值类型的工具类型 PromiseValue
// 首先提取到 then 方法中的函数类型,再通过这个函数类型的首个参数来提取出实际的值。
type Awaited<T> = T extends null | undefined
? T
: T extends object & { then(onfulfilled: infer F): any }
? F extends (value: infer V, ...args: any) => any
? Awaited<V>
: never
: T;
网友评论