Typescript 的
高级类型就是生成类型的类型。
内置高级类型
//file: node_modules/typescript/lib/lib.es5.d.ts
type Partial<T> = {
[P in keyof T]?: T[P]
}
type Required<T> = {
[P in keyof T]-?: T[P]
}
type Readonly<T> = {
readonly [P in keyof T]: T[P]
}
type Pick<T, K extends keyof T> = {
[P in K]: T[P]
}
type KeyOfAny = keyof any // string | number | symbol
type Reacord<K extends keyof any, T> = {
[P in K]: T
}
type Exclude<T, K> = T extends K ? never : T
type Extract<T, K> = T extends K ? T : never
// type Omit<T, K extends keyof T> = {
// [P in Exclude<keyof T, K>]: T[P]
// }
type Omit<T, K extends keyof T> = Pick<T, Exclude<keyof T, K>>
type NonNullable<T> = T extends null | undefined ? never : T
type Parameters<T extends (...args: any) => any> = T extends (...args: infer P) => any ? P : never
type ConstructorParameters<T extends new (...args: any) => any> = T extends new (...args: infer P) => any ? P : never
type ReturnType<T extends (...args: any) => any> = T extends (...args: any) => infer R ? R : any
type InstanceType<T extends new (...args: any) => any> = T extends new (...args: any) => infer R ? R : any
type Uppercase<S extends string> = intrinsic
type Lowercase<S extends string> = intrinsic
type Capitalize<S extends string> = intrinsic
type Uncapitalize<S extends string> = intrinsic
interface ThisType<T> { }
// this 详解: https://juejin.cn/post/6927507521783627790
type ThisParameterType<T> = T extends (this: infer U, ...args: any[]) => any ? U : unknown
type OmitThisParameter<T> = unknown extends ThisParameterType<T> ? T : T extends (...args: infer A) => infer R ? (...args: A) => R : T
集合操作
// 并集
type ToUnion<A, B> = A | B
type ToUnionDemo = ToUnion<'a'|'b'|'d', 'a'|'b'|'c'>
// 交集
type ToIntersection<A, B> = A extends B ? A : never
// type ToIntersectionDemo = ToIntersection<'a'|'b'|'d', 'a'|'b'|'c'>
// or
type ToIntersectionDemo = Extract<'a'|'b'|'d', 'a'|'b'|'c'>
// 差集
type Difference<A, B> = A extends B ? never : A
type ToDifference<A, B> = Difference<A | B, A & B>
// type ToDifferenceDemo = ToDifference<'a'|'b'|'d', 'a'|'b'|'c'>
// or
type ToDifferenceDemo = Exclude<'a'|'b'|'d', 'a'|'b'|'c'>
infer
// 核心:声明变量
// 获取 Promise 类型值的类型
type PromiseValue<T> = T extends Promise<infer U> ? U : T
type PromiseValueDemo = PromiseValue<Promise<{a: string}>>
// shift
type ShiftOfArr<T extends Array<any>> = T extends [any, ...infer U] ? U : []
type ShiftOfArrDemo = ShiftOfArr<[string, number, undefined]>
// unShift
type UnShiftOfArr<T extends Array<any>, V> = [V, ...T]
type UnShiftOfArrDemo = UnShiftOfArr<[string, number, undefined]>
// push
type PushOfArr<T extends Array<any>, V> = T extends [...infer U] ? [...U, V] : []
type PushOfArrDemo = PushOfArr<[string, number, undefined], null>
// pop
type PopOfArr<T extends Array<any>> = T extends [...infer U, infer L] ? U : []
type PopOfArrDemo = PopOfArr<[string, number, undefined]>
// trimLeft
type TrimLeft<S extends string> = S extends `${' ' | '\t' | '\n'}${infer R}` ? TrimLeft<R> : S
type TrimLeftDemo = TrimLeft<' 7yue '>
// trimRight
type TrimRight<S extends string> = S extends `${infer R}${' ' | '\t' | '\n'}` ? TrimRight<R> : S
type TrimRightDemo = TrimRight<' 7yue '>
// trim
type Trim<S extends string> = TrimRight<TrimLeft<S>>
type TrimDemo = Trim<' 7yue '>
// replace
type Replace<S extends string, F extends string, T extends string>
= S extends `${infer L}${F}${infer R}` ? Replace<`${L}${T}${R}`, F, T> : S
type ReplaceDemo = Replace<'7yue~mmmm~', 'm', 'z'>
// 将联合类型转为对应的交叉类型 (协变, 逆变)
type UnionToInterSection<T> = (T extends any ? (x: T) => any : never) extends (x: infer R) => any ? R : never
type UnionToInterSectionDemo = UnionToInterSection<{a: string} | {b: number} | {c: undefined}>
算数运算
// 条件判断 ==> extends
// 循环 ==> 递归
type NumberToArray<T extends number, R extends any[] = []> = R['length'] extends T ? R : NumberToArray<T, [...R, any]>
// 加法
type Add<L extends number, R extends number> = [...NumberToArray<L>, ...NumberToArray<R>]['length']
type AddDemo = Add<3, 4>
// 减法
type Sub<L extends number, R extends number>
= NumberToArray<L> extends [...NumberToArray<R>, ...infer Result] ? Result['length'] : never
type SubDemo =Sub<3, 1>
// 乘法
type Multi<L extends number, R extends number, CArr extends any[] = [], TArr extends any[] = []>
= CArr['length'] extends R ? TArr['length'] : Multi<L, R, [...CArr, any], [...TArr, ...NumberToArray<L>]>
type MultiDemo = Multi<3, 4>
// 除法
type Divide<L extends number, R extends number, TArr extends any[] = []>
= L extends 0 ? TArr['length'] : Divide<Sub<L, R>, R, [...TArr, any]>
type DivideDemo = Divide<12, 4>
简易加法表达式编译器
type ASTExpressionNode = {
type: 'operator' | 'expression'
left?: ASTExpressionNode
right?: ASTExpressionNode
value?: keyof NumberMap
}
type Parse<T> = T extends `${infer ExpressionA} + ${infer ExpressionB}`
? {
type: 'operator',
left: Parse<ExpressionA>,
right: Parse<ExpressionB>
}
: {
type: 'expression',
value: T extends keyof NumberMap ? T : never
}
type NumberToArray<T extends number, R extends any[] = []> = R['length'] extends T ? R : NumberToArray<T, [...R, any]>
type Add<L extends number, R extends number> = [...NumberToArray<L>, ...NumberToArray<R>]['length']
type GetValue<T extends ASTExpressionNode> = T['value'] extends string ? T['value'] : never
type GetLeft<T extends ASTExpressionNode> = T['left'] extends ASTExpressionNode ? T['left'] : never
type GetRight<T extends ASTExpressionNode> = T['right'] extends ASTExpressionNode ? T['right'] : never
// string to number
type NumberMap = {
'0': 0,
'1': 1,
'2': 2,
'3': 3,
'4': 4,
'5': 5,
'6': 6,
'7': 7,
'8': 8,
'9': 9,
}
type Evaluate<T extends ASTExpressionNode> = T['type'] extends 'expression'
? NumberMap[`${GetValue<T>}`]
: Add<Evaluate<GetLeft<T>>, Evaluate<GetRight<T>>>
type Calculator<T extends string> = Evaluate<Parse<T>>
type ParseDemo = Parse<'1 + 2'>;
type CalculatorDemo = Calculator<'1 + 2 + 7'>
Exclude
interface IToExclude {
a: string
b: number | undefined
c: undefined
d: null
e?: string
}
// 获取去除指定类型的字段组成的联合类型
type ExcludeTypeToUnionKey<T, K> = {
[P in keyof T]-?: [T[P]] extends [K] ? [K] extends [T[P]] ? never : P : P
}[keyof T]
type ExcludeTypeToUnionKeyDemo = ExcludeTypeToUnionKey<IToExclude, number | undefined>
// 获取去除指定类型的联合类型
type ExcludeKeyOfTypeToUnion<T, K> = {
[P in keyof T]-?: [T[P]] extends [K] ? [K] extends [T[P]] ? never : {[Q in P]: T[P]} : {[Q in P]: T[P]}
}[keyof T]
type ExcludeKeyOfTypeToUnionKey = ExcludeKeyOfTypeToUnion<IToExclude, number | undefined>
// 去除指定类型
type ExcludeKeyOfType<T, K> = {
[P in ExcludeTypeToUnionKey<T, K>]: T[P]
}
// or
// type ExcludeKeyOfType<T, K> = Pick<T, ExcludeTypeToUnionKey<T, K>> // Pick 保留了可选修饰符[?]
type ExcludeKeyOfTypeDemo = ExcludeKeyOfType<IToExclude, number | string>
Partial
interface IToPartial {
a: string
b: number | undefined
c?: string
d: number
}
// type ToOptional<T> = Partial<T>
type ToOptional<T> = {
[K in keyof T]?: T[K]
}
type ToOptionalDemo = ToOptional<IToPartial>
// 指定字段为可选
// type ToOptionalWithKey<T, K extends keyof T> = Partial<Pick<T, K>> & Omit<T, K>
type ToOptionalWithKey<T, K extends keyof T> = {
[P in K]?: T[P]
} & {
[P in Exclude<keyof T, K>]: T[P]
}
type ToOptionalWithKeyDemo = ToOptionalWithKey<IToPartial, 'a'>
// 去除可选类型后key组成的联合类型
type IsOptional<T, K extends keyof T> = Partial<Pick<T, K>> extends Pick<T, K> ? true : false
type ExcludeOptionalToUnionKey<T> = {
[P in keyof T]-?: IsOptional<T, P> extends true ? never : P
}[keyof T]
type ExcludeOptionalToUnionKeyDemo = ExcludeOptionalToUnionKey<IToPartial>
// 去除可选类型
type ExcludeOptional<T> = {
[P in ExcludeOptionalToUnionKey<T>]: T[P]
}
// or
// type ExcludeOptional<T> = Pick<T, ExcludeOptionalToUnionKey<T>>
type ExcludeOptionalDemo = ExcludeOptional<IToPartial>
Required
interface IToRequired {
a: string
b: number | undefined
c?: string
d: number
e?: symbol
}
// type ToRequired<T> = Required<T>
type ToRequired<T> = {
[K in keyof T]-?: T[K]
}
type ToRequiredDemo = ToRequired<IToRequired>
// 指定字段为必填
// type ToRequiredWithKey<T, K extends keyof T> = Required<Pick<T, K>> & Omit<T, K>
type ToRequiredWithKey<T, K extends keyof T> = {
[P in K]-?: T[P]
} & {
[P in Exclude<keyof T, K>]: T[P]
}
type ToRequiredWithKeyDemo = ToRequiredWithKey<IToRequired, 'a'>
// 去除必填类型后key组成的联合类型
type ExcludeRequiredToUnionKey<T> = {
[P in keyof T]-?: {} extends Pick<T, P> ? P : never
}[keyof T]
type ExcludeRequiredToUnionDemo = ExcludeRequiredToUnionKey<IToRequired>
// 去除必填类型
// type ExcludeRequired<T> = {
// [P in ExcludeRequiredToUnionKey<T>]: T[P]
// }
// or
type ExcludeRequired<T> = Pick<T, ExcludeRequiredToUnionKey<T>>
type ExcludeRequiredDemo = ExcludeRequired<IToRequired>
Readonly
interface IToReadonly {
readonly a: string
b: number | undefined
c?: string
d: number;
e?: symbol
}
// type ToReadonly<T> = Readonly<T>
type ToReadonly<T> = {
readonly [K in keyof T]: T[K]
}
type ToReadonlyDemo = ToReadonly<IToReadonly>
// 指定字段为只读
// type ToReadonlyWithKey<T, K extends keyof T> = Readonly<Pick<T, K>> & Omit<T, K>
type ToReadonlyWithKey<T, K extends keyof T> = {
readonly [P in K]: T[P]
} & {
[P in Exclude<keyof T, K>]: T[P]
}
type ToReadonlyWithKeyDemo = ToReadonlyWithKey<IToReadonly, 'a'>
// 去除只读类型后key组成的联合类型
// https://github.com/Microsoft/TypeScript/issues/27024#issuecomment-421529650
type IfEquals<X, Y, A, B> = (<T>() => T extends X ? 1 : 2) extends (<T>() => T extends Y ? 1 : 2) ? A : B;
type ExcludeReadonlyToUnionKey<T> = {
[P in keyof T]-?: IfEquals<{[Q in P]: T[P]}, {-readonly [Q in P]: T[P]}, P, never>
}[keyof T]
type ExcludeReadonlyToUnionKeyDemo = ExcludeReadonlyToUnionKey<IToReadonly>
// 去除只读类型
// type ExcludeReadonly<T> = {
// [P in ExcludeReadonlyToUnionKey<T>]: T[P]
// }
// or
type ExcludeReadonly<T> = Pick<T, ExcludeReadonlyToUnionKey<T>>
type ExcludeReadonlyDemo = ExcludeReadonly<IToReadonly>