模式匹配做提取 数组类型 提取数组第一个元素的类型
1 2 3 type GetFirst<Arr extends unknown[]> = Arr extends [infer First, ...unknown[]] ? First : never ;
提取数组最后一个元素的类型
1 2 3 type GetLast<Arr extends unknown[]> = Arr extends [...unknown[], infer Last] ? Last : never ;
取去掉最后一个元素的数组
1 2 3 4 5 type PopArr<Arr extends unknown[]> = Arr extends [] ? [] : Arr extends [...infer Rest, unknown] ? Rest : never ;
字符串类型 字符串是否以某个特定字符开头
1 2 3 4 type StartWidth< Str extends string , Prefix extends String > = Str extends `${Prefix} ${string } ` ? true : false ;
将字符串中某个特定的部分替换成别的字符串
1 2 3 4 5 6 7 type ReplaceStr< Str extends string , From extends string , To extends string > = Str extends `${infer Prefix} ${From} ${infer Suffix} ` ? `${Prefix} ${To} ${Suffix} ` : Str;
字符串去除右空格
1 2 3 4 5 6 type TrimStrRight<Str extends string > = Str extends `${infer Rest} ${ | " " | "\n" | "\t" } ` ? TrimStrRight<Rest> : Str;
函数类型 提取函数参数的类型
1 2 3 4 5 type GetParameters<Func extends Function > = Func extends ( ...args: infer Args ) => unknown ? Args : never ;
提取函数返回值的类型
1 2 3 4 5 type GetReturnType<Func extends Function > = Func extends ( ...args: any [] ) => infer ReturnType ? ReturnType : never ;
构造器 提取构造器参数的类型
1 2 3 4 type GetInstanceParameters<ConstructorType extends new (...args: any ) => any > = ConstructorType extends new (...args: infer ParametersType) => any ? ParametersType : never ;
提取构造器返回值类型
1 2 3 4 type GetInstanceReturnType<ConstructorType extends new (...args: any ) => any > = ConstructorType extends new (...args: any ) => infer InstanceType ? InstanceType : never ;
索引类型 提取 props 中 ref 值的类型
1 2 3 4 5 type GetRefProps<Props> = "ref" extends keyof Props ? Props extends { ref?: infer Value | undefined } ? Value : never : never ;
重新构造做变换 TypeScript 的 type、infer、类型参数声明的变量都不能修改,想对类型做各种变换产生新的类型就需要重新构造。
数组类型的构造 给数组/元组添加新类型
1 type Push<Arr extends unknown[], Ele> = [...Arr, Ele];
元组重组
1 2 3 4 5 6 7 8 9 10 11 12 13 14 type tuple1 = [1 , 2 ];type tuple2 = ["guang" , "dong" ];type tuple = [[1 , "guang" ], [2 , "dong" ]];type Zip<One extends unknown[], Other extends unknown[]> = One extends [ infer OneFirst, ...infer OneRest ] ? Other extends [infer OtherFirst, ...infer OtherRest] ? [[OneFirst, OtherFirst], ...Zip<OneRest, OtherRest>] : [] : [];
字符串类型的构造 将字符串首字母大写
1 2 3 4 type CapitalizeStr<Str extends string > = Str extends `${infer First} ${infer Rest} ` ? `${Uppercase<First>} ${Rest} ` : Str;
将字符串下划线转驼峰
```tstype CamelCase<Str extends string> = Str extends
${infer Left}_${infer Right}${infer Rest}?
${Left}${Uppercase}${CamelCase}` Str; 1 2 3 4 5 6 7 8 **删除字符串子串** ```ts type DropSubStr<Str extends string, SubStr extends string> = Str extends `${infer Prefix}${SubStr}${infer Suffix}` ? DropSubStr<`${Prefix}${Suffix}`, SubStr> : Str;
函数类型的构造 给函数添加一个参数
1 2 3 4 5 type AppendArgument<Func extends Function , Arg> = Func extends ( ...args: infer Args ) => infer ReturnType ? (...args: [...Args, Arg] ) => ReturnType : never ;
索引类型的构造 索引类型是聚合多个元素的类型。比如 class 和对象都是索引类型。索引类型的元素的类型只能是 string、number 或者 Symbol 等类型。
索引类型的每个元素的类型可以添加修饰符:readonly(只读)、?(可选)。
映射类型语法
1 2 3 type Mapping<Obj extends object > = { [Key in keyof Obj]: Obj[Key]; };
用 as 做重映射改变索引类型的 Key 转成大写
1 2 3 type UppercaseKey<Obj extends object > = { [Key in keyof Obj as Uppercase<Key & string >]: Obj[Key]; };
因为这里索引的类型可能是 string、number 或 symbol 类型,但是这里转成大写只能是限定为 string。
TS 内置高级类型 Record
1 type Record<K extends string | number | symbol, T> = { [P in K]: T };
UppercaseKey 重写版:用 Record 来约束索引类型而不是 object
1 2 3 type UppercaseKey<Obj extends Record<string , any >> = { [Key in keyof Obj as Uppercase<Key & string >]: Obj[Key]; };
给索引类型添加只读的高级类型
1 2 3 type ToReadonly<T> = { readonly [Key in keyof T]: T[Key]; };
给索引类型添加可选的高级类型
1 2 3 type ToPartial<T> = { [Key in keyof T]?: T[Key]; };
给索引类型去掉只读修饰符
1 2 3 type ToMutable<T> = { -readonly [Key in keyof T]: T[Key]; };
给索引类型去掉可选修饰符
1 2 3 type ToRequired<T> = { [Key in keyof T]-?: T[Key]; };
返回特定值的类型的索引类型
1 2 3 type FilterByValueType<Obj extends Record<string , any >, ValueType> = { [Key in keyof Obj as Obj[Key] extends ValueType ? Key : never ]: Obj[Key]; };
递归复用做循环 Promise 的递归复用 提取 Promise 值的类型
1 2 3 4 5 6 7 type DeepPromiseValueType<P extends Promise <unknown>> = P extends Promise < infer ValueType > ? ValueType extends Promise <unknown> ? DeepPromiseValueType<ValueType> : ValueType : never ;
提取 Promise 值的类型简化版
1 2 3 type DeepPromiseValueType<T> = T extends Promise <infer ValueType> ? DeepPromiseValueType<ValueType> : never ;
数组类型的递归 反转元组
1 2 3 4 5 6 type ReversrArr<Arr extends unknown[]> = Arr extends [ infer First, ...infer Rest ] ? [...ReversrArr<Rest>, First] : Arr;
查找元素
1 2 3 4 5 6 7 8 9 10 type Includes<Arr extends unknown[], FindItem> = Arr extends [ infer First, ...infer Rest ] ? IsEqual<First, FindItem> extends true ? true : Includes<Rest, FindItem> : false ; type IsEqual<A, B> = (A extends B ? true : false ) & (B extends A ? true : false );
删除元素
1 2 3 4 5 6 7 8 9 10 11 type RemoveItem< Arr extends unknown[], Item, Result extends unknown[] = [] > = Arr extends [infer First, ...infer Rest] ? IsEqual<First, Item> extends true ? RemoveItem<Rest, Item, Result> : RemoveItem<Rest, Item, [...Result, First]> : Result; type IsEqual<A, B> = (A extends B ? true : false ) & (B extends A ? true : false );
构造指定类型的数组
1 2 3 4 5 type BuildArray< Length extends number , Ele = unknown, Arr extends unknown[] = [] > = Arr["length" ] extends Length ? Arr : BuildArray<Length, Ele, [...Arr, Ele]>;
字符串类型的递归 替换子串
1 2 3 4 5 6 7 type ReplaceAll< Str extends string , From extends string , To extends string > = Str extends `${infer Left} ${From} ${infer Right} ` ? `${Left} ${To} ${ReplaceAll<Right, From, To>} ` : Str;
提取字符做联合类型
1 2 3 4 type StringToUnion<Str extends string > = Str extends `{infer First}${infer Rest} ` ? First | StringToUnion<Rest> : never ;
反转字符串
1 2 3 type ReverseStr<Str extends string > = Str extends `${infer First} ${infer Rest} ` ? `${ReverseStr<Rest>} ${First} ` : Str;
对象类型的递归 深度递归
1 2 3 4 5 6 7 8 9 type DeepToReadonly<T extends Record<string , any >> = T extends any ? { readonly [Key in keyof T]: T[Key] extends Object ? T[Key] extends Function ? T[Key] : DeepToReadonly<T[Key]> : T[Key]; } : never ;
数组长度做计算 数组长度实现加减乘除 加法
1 2 3 4 5 6 7 8 9 10 type BuildArray< Length extends number , Ele = unknown, Arr extends unknown[] = [] > = Arr["length" ] extends Length ? Arr : BuildArray<Length, Ele, [...Arr, Ele]>; type Add<Num1 extends number , Num2 extends number > = [ ...BuildArray<Num1>, ...BuildArray<Num2> ]["length" ];
减法
1 2 3 4 5 6 type Subtract< Num1 extends number , Num2 extends number > = BuildArray<Num1> extends [...BuildArray<Num2>, ...infer Rest] ? Rest["length" ] : never ;
乘法
1 2 3 4 5 6 7 type Multiple< Num1 extends number , Num2 extends number , ResultArr extends unknown[] = [] > = Num2 extends 0 ? ResultArr["length" ] : Multiple<Num1, Subtract<Num2, 1 >, [...ResultArr, ...BuildArray<Num1>]>;
除法
1 2 3 4 5 6 7 type Divide< Num1 extends number , Num2 extends number , ResultArr extends unknown[] = [] > = Num1 extends 0 ? ResultArr["length" ] : Divide<Subtract<Num1, Num2>, Num2, [...ResultArr, unknown]>;
数组长度实现计数 计算字符串长度
1 2 3 4 5 6 type StrLen< Str extends string , CountArr extends unknown[] = [] > = Str extends `${string } ${infer Rest} ` ? StrLen<Rest, [...CountArr, unknown]> : CountArr["length" ];
比较 2 个数值谁更大
1 2 3 4 5 6 7 8 9 10 11 type GreaterThan< Num1 extends number , Num2 extends number , CountArr extends unknown[] = [] > = Num1 extends Num2 ? false : CountArr["length" ] extends Num2 ? true : CountArr["length" ] extends Num1 ? false : GreaterThan<Num1, Num2, [...CountArr, unknown]>;
实现斐波那契数列
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 type FibonacciLoop< PrevArr extends unknown[], CurrentArr extends unknown[], IndexArr extends unknown[] = [], Num extends number = 1 > = IndexArr["length" ] extends Num ? CurrentArr["length" ] : FibonacciLoop< CurrentArr, [...PrevArr, ...CurrentArr], [...IndexArr, unknown], Num >; type Fibonacci<Num extends number > = FibonacciLoop<[1 ], [], [], Num>;
聚合分散可简化 分布式条件类型 当类型参数为联合类型,并且在条件类型左边直接引用该类型参数的时候,TypeScript 会把每一个元素单独传入来做类型运算,最后再合并成联合类型,这种语法叫做分布式条件类型。
1 2 3 4 type Union = "a" | "b" | "c" ;type UppercaseA<Item extends string > = Item extends "a" ? Uppercase<Item> : Item;
这和联合类型遇到字符串时的处理一样:
1 2 3 type Union = "a" | "b" ;type str = `${Union} ~` ;
数组转联合类型 1 2 3 type Arr = ["a" , "b" , "c" ];type UnionArr = Arr[number ];
判断是否是联合类型 1 type isUnion<A, B = A> = A extends A ? ([B] extends [A] ? false : true ) : never ;
当 A 是联合类型时:
A extends A 这种写法是为了触发分布式条件类型,让每个类型单独传入处理的,没别的意义。
A extends A 和 [A] extends [A] 是不同的处理,前者是单个类型和整个类型做判断,后者两边都是整个联合类型,因为只有 extends 左边直接是类型参数才会触发分布式条件类型。
BEM 1 2 3 4 5 type BEM< Block extends string , Element extends string [], Modifiers extends string [] > = `${Block} __${Element[number ]} --${Modifiers[number ]} ` ;
全组合 1 2 3 4 5 6 7 8 9 type Combination<A extends string , B extends string > = A | B | `${A} ${B} ` | `${B} ${A} ` type AllCombinations<A extends string , B extends string = A> = A extens A ? Combination<A, AllCombinations<Exclude<B, A>>> : never ;
特殊特性要记清 IsAny any 类型与任何类型的交叉都是 any,也就是 1 & any 结果是 any。
1 type IsAny<T> = "a" extends 1 & T ? true : false ;
IsEqual 1 2 3 4 5 6 7 8 9 10 type IsEqual<A, B> = (A extends B ? true : false ) & (B extends A ? true : false ); type IsEqual2<A, B> = (<T>() => T extends A ? 1 : 2 ) extends < T >() => T extends B ? 1 : 2 ? true : false ;
IsUnion 1 type IsUnion<A, B> = A extends A ? ([B] extends [A] ? false : true ) : never ;
IsNever never 在条件类型中也比较特殊,如果条件类型左边是类型参数,并且传入的是 never,那么直接返回 never。
1 2 3 4 5 6 type TestNever<T> = T extends number ? 1 : 2 ;type result = TestNever<never >;type IsNever<T> = [T] extends [never ] ? true : false ;
除此之外,any 在条件类型中也比较特殊,如果类型参数为 any,会直接返回 trueType 和 falseType 的合并。
1 2 3 type TestAny<T> = T extends number ? 1 : 2 ;type result = TestAny<any >;
IsTuple 元组类型的 length 是数字字面量,而数组的 length 是 number。
1 2 3 4 5 6 7 8 9 type IsTuple<T> = T extends [...infer Eles] ? NotEqual<Ele["length" ], number > : false ; type NotEqual<A, B> = (<T>() => T extends A ? 1 : 2 ) extends < T >() => T extends B ? 1 : 2 ? false : true ;
UnionToIntersection 联合类型转交叉类型。
1 2 3 4 5 type UnionToIntersecion<U> = (U extends U ? (x: U ) => unknown : never ) extends ( x: infer R ) => unknown ? R : never ;
GetOptional 提取索引类型中的可选索引。
1 2 3 4 5 6 type GetOptional<Obj extends Record<string , any >> = { [Key in keyof Obj as {} extends Pick<Obj, Key> ? Key : never ]: Obj[Key]; }; type Pick<T, K extends keyof T> = { [P in K]: T[P] };
GetRequired 提取索引类型中的非可选索引构造成新的索引类型。
1 2 3 type GetRequired<Obj extends Record<string , any >> = { [Key in keyof Obj as {} extends Pick<Obj, Key> ? never : Key]: Obj[Key]; };
RemoveIndexSignature 过滤掉索引类型中的可索引签名,构造成一个新的索引类型。 索引签名的特性:索引签名不能构造成字符串字面量类型,因为它没有名字,而其他索引可以
1 2 3 type RemoveIndexSignature<Obj extends Record<string , any >> = { [Key in keyof Obj as Key extends `${infer Str} ` ? Str : never ]: Obj[Key]; };
ClassPublicProps 过滤 class 的 public 属性。 根据特性:keyof 只能拿到 class 的 public 索引,private 和 protected 的索引会被忽略。
1 2 3 type ClassPublicProps<Obj extends Record<string , any >> = { [Key in keyof Obj]: Obj[Key]; };
as const TypeScript 默认推导出来的类型并不是字面量类型。
1 2 3 4 5 6 7 8 9 const obj = { a: 1 , b: 2 , }; type objType = typeof obj;
如果想要推到出字面量,就需要用 as const:
1 2 3 4 5 6 7 const arr = [1 , 2 , 3 ];type arrType = typeof arr;const arr2 = [1 , 2 , 3 ] as const ;type arrType2 = typeof arr2;
反转 3 个元素的元组类型,需要加上 readonly 才能匹配成功。
1 2 3 type ReverseArr<Arr> = Arr extends readonly [infer A, infer B, infer C] ? [C, B, A] : never ;
练一练 实现 ParseQueryString 将 ‘a=1&b=2&c=3’ 转成 {a: 1, b: 2, c: 3}
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 type ParseQueryString<Str extends string > = Str extends `${infer Param} &${infer Rest} ` ? MergeParams<ParseParams<Param>, ParseQueryString<Rest>> : ParseParam<Str>; type ParseParams<Param extends string > = Param extends `${infer Key} =${infer Value} ` ? { [K in Key]: Value; } : Record<string , any >; type MergeParams< OneParam extends Record<string , any >, OtherParam extends Record<string , any > > = { [Key in keyof OneParam | keyof OtherParam]: Key extends keyof OneParam ? Key extends keyof OtherParam ? MergeValue<OneParam[Key], OtherParam[Key]> : OneParam[Key] : Key extends keyof OtherParam ? OtherParam[Key] : never ; }; type MergeValue<One, Other> = One extends Other ? One : Other extends unknown[] ? [One, ...Other] : [One, Other];
TS 内置的高级类型 Parameters 提取函数类型的参数类型
1 2 3 4 5 type Parameters<T extends (...args: any ) => any > = T extends ( ...args: infer P ) => any ? P : never ;
ReturnType 提取函数类型的返回值类型
1 2 3 4 5 type ReturnType<T extends (...args: any ) => any > = T extends ( ...args: any ) => infer R ? R : never ;
ConstructorParameters 提取构造函数的参数类型
1 2 3 4 5 type ConstructorParameters<T extends new (...ars: any ) => any > = T extends new ( ...args: infer P ) => any ? P : never ;
InstanceType 提取构造器返回值类型
1 2 3 4 5 type InstanceType<T extends new (...ars: any ) => any > = T extends new ( ...ars: any ) => infer R ? R : any ;
ThisParameterType 提取函数参数中 this 的类型
1 2 3 type ThisParameterType<T> = T extends (this : infer U, ...args: any []) => any ? U : unknown;
OmitThisParameter 去除函数参数中的 this 类型,并且返回一个新的类型
1 2 3 4 5 6 type OmitThisParameter<T> = unknown extends ThisParameterType<T> ? T : T extends (...args: infer A) => infer R ? (...args: A) => infer R : T;
Partial 把索引类型的所有索引变成可选类型
1 2 3 type Partial<T> = { [P in keyof T]?: T[P]; };
Required 把索引类型里可选索引改成必选索引
1 2 3 type Required<T> = { [P in keyof T]-?: T[P]; };
Readonly 索引类型的索引添加只读
1 2 3 type Readonly<T> = { readonly [P in keyof T]: T[P]; };
Pick 过滤出指定的索引类型
1 2 3 type Pick<T, K extends keyof T> = { [P in K]: T[P]; };
Record 创建索引类型
keyof any 会返回 string | number | symbol
1 2 3 type Record<K extends keyof any , T> = { [P in K]: T; };
如果 Record 里的第一个参数是 string | number | symbol,那么创建的就是索引签名索引类型:
1 2 3 4 type RecordRes = Record<string , number >;
Exclude 去掉联合类型中的某些类型,即取差集
联合类型当作为类型参数出现在条件类型左边时,会被分散成单个类型传入,这叫做分布式条件类型。
1 type Exclude<T, U> = T extends U ? never : T;
提取联合类型中的某些类型,即取交集
1 type Extract<T, U> = T extends U ? T : never ;
Omit 去掉某部分索引类型的索引构成新索引类型
1 type Omit<T, K in keyof any > = Pick<T, EXclude<keyof T, K>>;
Awaited 提取 Promise 的返回值类型
1 2 3 4 5 6 7 8 type Awaited<T> = T extends null | undefined ? T : T extends object & { then(onfulfilled: infer F): any } ? F extends ((value, infer V, ...ars: any ) => any ) ? Awaited<V> : never : T;
NonNullable 判断是否是空类型,即不是 null 或 undefined
1 type NonNullable<T> = T extends null | unfefined ? never : T;
Uppercase、Lowercase、Capitalize、Uncapitalize 这几个类型分别是实现大写、小写、首字母大写、去掉首字母大写的。 他们的实现是直接用 js 实现的。
综合实战 KebabCaseToCamelCase ‘aa-bb-cc’ 这种是 KebabCase,而 ‘aaBbCc’ 这种是 CamelCase
1 2 3 4 type KebabCaseToCamelCase<Str extends string > = Str extends `${infer Item} -${infer Rest} ` ? `${Item} ${KebabCaseToCamelCase<Capitalize<Rest>>} ` : Str;
CamelCaseToKebabCase 1 2 3 4 5 6 type CamelCaseToKebabCase<Str extends string > = Str extends `${infer First} ${infer Rest} ` ? First extends Lowercase<First> ? `${First} ${CamelCaseToKebabCase<Rest>} ` : `-${Lowercase<First>} ${CamelCaseToKebabCase<Rest>} ` : Str;
Chunk 对数组做分组,比如 1、2、3、4、5 的数组,每两个为 1 组,那就可以分为 1、2 和 3、4 以及 5 这三个 Chunk。
1 2 3 4 5 6 7 8 9 10 type Chunk< Arr extends unknown[], ItemLen extends number , CurItem extends unknown[] = [], Res extends unknown[] = [] > = Arr extends [infer First, ...infer Rest] ? CurItem["length" ] extends ItemLen ? Chunk<Rest, ItemLen, [First], [...Res, CurItem]> : Chunk<Rest, ItemLen, [...CurItem, First], Res> : [...Res, CurItem];
TupleToNestedObject 根据数组类型,比如 [‘a’, ‘b’, ‘c’] 的元组类型,再加上值的类型 ‘xxx’,构造出这样的索引类型:
1 2 3 4 5 6 7 { a: { b: { c: "xxx" ; } } }
1 2 3 4 5 6 7 8 9 10 11 12 type TupleToNestedObject<Tuple extends unknown[], ValueType> = Tuple extends [ infer First, ...infer Rest ] ? { [Key in First as Key extends keyof any ? Key : never ]: Rest extends unknown[] ? TupleToNestedObject<Rest, ValueType> : ValueType; } : ValueType;
PartialObjectPropByKeys 把一个索引类型的某些 Key 转为 可选的,其余的 Key 不变。
1 2 3 4 5 6 7 8 9 10 11 type PartialObjectPropByKeys< Obj extends Record<string , any >, Key extends keyof any > = Partial<Pick<Obj, Extract<keyof Obj, Key>>> & Omit<Obj, Key>; type PartialObjectPropByKeys2< Obj extends Record<string , any >, KeyType extends keyof any > = { [Key in keyof Obj as Key extends KeyType ? Key? : Key]: Obj[Key]; };
函数重载的三种写法 第一种
1 2 3 4 5 function add (a: number , b: number ): number ;function add (a: string , b: string ): string ;function add (a: any , b: any ) { return a + b; }
第二种
1 2 3 4 5 interface Func { (a: number , b: number ): number ; (a: string , b: string ): string ; } const add: Func = (a: any , b: any ) => a + b;
第三种
1 2 type Func = ((a: number , b: number ) => number ) & ((a: string , b: string ): string )const add: Func = (a: any , b: any ) => a + b;
UnionToTuple 将联合类型转成元组。
1 2 3 4 5 6 7 8 9 10 11 12 type UnionToTuple<T> = UnionToIntersection< T extends any ? () => T : never > extends () => infer ReturnType ? [...UnionToTuple<Exclude<T, ReturnType>>, ReturnType] : []; type UnionToIntersection<U> = ( U extends U ? (x: U ) => unknown : never ) extends (x: infer R) => unknown ? R : never ;
join 实现一个类似的效果,将:
1 2 const res = join("-" )("guang" , "and" , "dong" );
join 代码实现
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 declare function join <Delimiter extends string >( delimiter: Delimiter ): <Items extends string []>(...parts: Items ) => JoinType <Items , Delimiter > ;type JoinType< Items extends any [], Delimiter extends string , Result extends string = "" > = Items extends [infer First, ...infer Rest] ? JoinType<Rest, Delimiter, `${Result} ${First & string } -` > : RemoveLastDelimiter<Result>; type RemoveLastDelimiter<Str extends string > = Str extends `${infer Rest} -` ? Rest : Str;
AllKeyPath 拿到一个索引类型的所有 key 的路径。
1 2 3 4 5 6 7 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];
Defaultize 实现这样一个高级类型,对 A、B 两个索引类型做合并,如果是只有 A 中有的不变,如果是 A、B 都有的就变为可选,只有 B 中有的也变为可选。
1 2 3 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>>>;
infer extends 枚举值转联合类型 以下会把枚举的数值类型转成字符串类型。
1 2 3 4 5 6 7 enum Code { a = 111 , b = 222 , c = "abc" , } type res = `${Code} ` ;
StrToNum 使用 infer extends 后就就可以正常使用了。
1 2 3 4 5 6 7 8 enum Code { a = 111 , b = 222 , c = "abc" , } type StrToNum<Str> = Str extends `${infer Num extends number } ` ? Num : Str;type res = StrToNum<`${Code} ` >;