type Extract<T, U> = T extends U ? T : never;
type Exclude<T, U> = T extends U ? never : T
type Record<K extends keyof any, T> = { [P in K]: T };
type Pick<T, K extends keyof T> = { [P in K]: T[P] };
type Omit<T, K extends keyof any> = Pick<T, Exclude<keyof T, K>>
type Partial0<T> = { [P in keyof T]?: T[P] };
type Required0<T> = { [P in keyof T]-?: T[P] };
type Readonly0<T> = { readonly [P in keyof T]: T[P] };
大写,小写,首字母大写,字母小写
Uppercase
、Lowercase
、Capitalize
、Uncapitalize
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;
// 提取函数 参数类型
type Parameters0<T extends (...args: any) => any> =
T extends (...args: infer P) => any ? P : never
// 提取函数 返回类型
type ReturnType0<T extends (...args: any) => any> =
T extends (...args: any) => infer R ? R : never
// 提取函数 this类型
type ThisParameterType0<T> =
T extends ( this: infer U, ...args: any[] ) => any
? U : unknown
// 移除函数 this类型
type OmitThisParameter0<T> =
unknown extends ThisParameterType<T>
? T : T extends (...args: infer A) => infer R
? (...args: A) => R : T
// 提取构造器 参数类型
type ConstructorParameters0<
T extends abstract new (...args: any) => any
> = T extends abstract new (...args: infer P) => any
? P : never
// 提取构造器 返回类型(实例)
type InstanceType0<
T extends abstract new (...args: any) => any
> = T extends abstract new (...args: any) => infer R
? R : never
这里尝试写, 删除函数this类型, 暴露了两个问题
this必须显示声明类型, 数组类型 不能直接在函数中参数展开
// 这里的实现方式也是错的
type OmitThisParameter0<T> =
// this: any 这里any必须加,
T extends (this, ...args: infer A) => infer R
// ...A 这里必须改 ...args:A, 因为A是数组类型,不能参数展开
? (...A) => R : T;
提取函数This类型必须显示声明this,即变量名必须写this
// 提取函数第一个参数类型,和提取this只差个参数名, 可见this必须显示声明
type FirstParameter<T> =
T extends ( arg1: infer A, ...args: any[] ) => any
? A : never
type NthParameter<T, N extends number> =
T extends (...args: infer P) => any
? P[N] : never;
要求
// { a: ["1", "2"]; b: "2"; c: "3"; }
type ParseQueryStringResult = ParseQueryString<'a=1&a=2&b=2&c=3'>
// 工具,解析形如 key=value 的字符串为对象类型
type ParseParam<Param extends string> =
Param extends `${infer Key}=${infer Value}`
// 直接写 {[Key]: Value} Key会被识别为字面量而非变量
? {[K in Key]: Value}
: {}
// 工具: Key相同的两个value合并为数组
// 注意: value本身可能已经是数组,由于是从后往前,所以只有Other可能是数组
type MergeValues<One, Other> =
One extends Other
// 俩value相等, 随便返回谁
? One
// 俩value不相等, 开始合并
: Other extends unknown[]
// Other是数组, 解构other合并
? [One, ...Other]
// Other不是数组, 直接合并
: [One, Other]
// 第二层,这里都是ParseParam过的数据,从<{b:3}, {c:4}>开始
type MergeParams<
T extends Record<string, any>,
U extends Record<string, any>
> = {
// 遍历两个对象的key
[Key in keyof T | keyof U]:
Key extends keyof T
? Key extends keyof U
// Key在1中,又在2中,value就要合并为数组
? MergeValues<T[Key], U[Key]>
// Key在1中,不在2中,返回1的value
: T[Key]
: Key extends keyof U
// Key不在1中,在2中,返回2的value
? U[Key]
// Key不在1中,不在2中,返回never
: never
}
// 第一层
type ParseQueryString<Str extends string> =
Str extends `${infer Param}&${infer Rest}`
// MergeParams 会在回溯阶段从后往前执行,也就是说最后两个参数会先合并,然后往前推
? MergeParams< ParseParam<Param>, ParseQueryString<Rest> >
// 到这里其实是,最后一个参数,直接parse并返回上一层,然后开始 MergeParams
: ParseParam<Str>
// { a: ["1", "2"]; b: "2"; c: "3"; }
type ParseQueryStringResult = ParseQueryString<'a=1&a=2&b=2&c=3'>
keyof T | keyof U
不能写成 keyof (T | U)
,这样是拿交集的Key
keyof 是一种内置操作符, 联合类型不对 keyof 分发
要求
// "aaaBbbCcc"
type testKebaCaseToCamelCase = KebaCaseToCamelCase<'aaa-bbb-ccc'>
// "aaa-bbb-ccc"
type testCamelCaseToKebaCase = CamelCaseToKebaCase<'aaaBbbCcc'>
type KebaCaseToCamelCase<T extends string> =
T extends `${infer First}-${infer Rest}`
? `${First}${KebaCaseToCamelCase<Capitalize<Rest>>}`
: T
// "aaaBbbCcc"
type testKebaCaseToCamelCase = KebaCaseToCamelCase<'aaa-bbb-ccc'>
type CamelCaseToKebaCase<T extends string> =
T extends `${infer First}${infer Rest}`
? First extends Lowercase<First>
? `${First}${CamelCaseToKebaCase<Rest>}`
: `-${Lowercase<First>}${CamelCaseToKebaCase<Rest>}`
: T
// "aaa-bbb-ccc"
type testCamelCaseToKebaCase = CamelCaseToKebaCase<'aaaBbbCcc'>
字符串不需要 增加结果储存变量
要求
// [[1, 2, 3], [4, 5, 6], [7, 8, 9], [10]]
type testChunk = Chunk<[1, 2, 3, 4, 5, 6, 7, 8, 9, 10], 3>
type Chunk<
T extends unknown[],
ItemLen extends number,
CurItem extends unknown[] = [],
R extends unknown[] = []
> = T extends [infer First, ...infer Rest]
? CurItem['length'] extends ItemLen
? Chunk<Rest, ItemLen, [First], [...R, CurItem]>
: Chunk<Rest, ItemLen, [...CurItem, First], R>
: [...R, CurItem]
// [[1, 2, 3], [4, 5, 6], [7, 8, 9], [10]]
type testChunk = Chunk<[1, 2, 3, 4, 5, 6, 7, 8, 9, 10], 3>
// { a: { b: { c: 'xxx' } } }
type testTupleToNestedObject =
TupleToNestedObject<['a', 'b', 'c'], 'xxx'>
type TupleToNestedObject<
Tuple extends unknown[],
Value
> = Tuple extends [infer First, ...infer Rest]
? { [Key in First as Key extends keyof any ? Key : never]
: Rest extends unknown[]
? TupleToNestedObject<Rest, Value>
: Value }
: Value
过滤key,再给value 递归调用Rest进行赋值
[Key in First as Key extends keyof any ? Key : never]
过滤Key,应该是常用写法了,可以记
// { name?: string | undefined; age: number; address: string; }
type testPartialObjectPropByKeys = PartialObjectPropByKeys<
Dong,
'name'
>
interface Dong {
name: string
age: number
address: string
}
type Copy<Obj extends Record<string, any>> =
{ [Key in keyof Obj]: Obj[Key] }
type PartialObjectPropByKeys<
T extends Record<string, any>,
Key extends keyof any
> = Copy< Partial<Pick<T, Extract<keyof T, Key>>> & Omit<T, Key> >
// { name?: string | undefined; age: number; address: string; }
type testPartialObjectPropByKeys =
PartialObjectPropByKeys< Dong, 'name' >
返回值类型与当时传入参数有关,需要动态生成类型
const func = (a: boolean, b: number, c: string) => {}
// (arg: boolean) => (arg: number) => (arg: string) => never
const curriedFunc = currying(func)
type CurriedFunc<Params, Return> =
Params extends [ infer Arg, ...infer Rest ]
? (arg: Arg) => CurriedFunc<Rest, Return>
: never
declare function currying<Func>(fn: Func):
Func extends (...args: infer Params) => infer Result
? CurriedFunc<Params, Result>
: never
// 使用 interface 表达 currying 函数的类型签名
interface Currying {
<Func>(fn: Func):
Func extends (...args: infer Params) => infer Result
? CurriedFunc<Params, Result>
: never
}
const func = (a: boolean, b: number, c: string) => {}
// (arg: boolean) => (arg: number) => (arg: string) => never
const curriedFunc = currying(func)
// (arg: boolean) => (arg: number) => (arg: string) => never
declare const currying2: Currying;
const curriedFunc2 = currying2(func)
declare function
是直接声明一个 实际存在的函数(通常由 JS 提供或实现)
type Obj = {
a: {
b: {
b1: string
b2: string
}
c: {
c1: string
c2: string
}
}
}
// "a" | "a.b" | "a.c" | "a.b.b1" | "a.b.b2" | "a.c.c1" | "a.c.c2"
type AllKeyPathRes = AllKeyPath<Obj>
type AllKeyPath<Obj extends Record<string, any>> = {
[Key in keyof Obj]: Key extends string
? Obj[Key] extends Record<string, any>
? Key | `${Key}.${AllKeyPath<Obj[Key]>}`
: Key
: never
}[keyof Obj]
要求 a有b没有 或 a没有b有 的属性变为 可选属性
type AA = { aaa: 111; bbb: 222 }
type BB = { bbb: 222; ccc: 333 }
// { aaa: 111; bbb?: 222 | undefined; ccc?: 333 | undefined; }
type DefaultizeRes = Copy<Defaultize<AA, BB>>
type Defaultize<A, B> = Pick<A, Exclude<keyof A, keyof B>> &
Partial<Pick<A, Extract<keyof A, keyof B>>> &
Partial<Pick<B, Exclude<keyof B, keyof A>>>
type Copy<Obj extends Record<string, any>> = {
[Key in keyof Obj]: Obj[Key]
}
type Separator = '-' | '.' | '/';
type Num = 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9;
type Num2 = Num | 0
type YY = `19${Num2}${Num2}` | `20${Num2}${Num2}`;
type MM = `0${Num}` | `1${0 | 1 | 2}`;
type DD = `${0}${Num}` | `${1 | 2}${Num2}` | `3${0 | 1}`;
type GenStr<Type extends string> =
Type extends 'YY'
? YY
: Type extends 'MM'
? MM
: DD;
type FormatDate<Pattern extends string> =
Pattern extends `${infer Aaa}${Separator}${infer Bbb}${Separator}${infer Ccc}`
? Pattern extends `${Aaa}${infer Sep}${Bbb}${infer _}${Ccc}`
? `${GenStr<Aaa>}${Sep}${GenStr<Bbb>}${Sep}${GenStr<Ccc>}`
: never
: never;
const a: FormatDate<'YY-MM-DD'> = '2023-01-02';
const b: FormatDate<'DD/MM/YY'> = '01/02/2024';
const c: FormatDate<'DD/MM/YY'> = '2024-01-02';