-
Notifications
You must be signed in to change notification settings - Fork 0
Description
How to use recursion
Add generic params to pass recursive params.
Example:
How to count for Array
Use the length of the Array instance. Examples:
How to transform number to string
Use the template literal and infer.
Example: Absolute
How to transform string to number
Use string to compare and Array to count.
Example:
type ToNumber<S extends string, A extends any[] = []> = `${A['length']}` extends S
? A['length'] : ToNumber<S, [any, ...A]>
ToNumber<'0'> // 0
ToNumber<'10'> // 10How to access some parts of string or Array
Use multiple infer keywords.
Example: StringToUnion
How to detect if a string or input value needs transformation
Compare the input with the output using extends.
Example:
type isCapitalizable<S extends string> = S extends Capitalize<S> ? false : true
type foo = isCapitalizable<'Foo'> //false
type bar = isCapitalizable<'bar'> //trueHow to add transformation except for the first time
Set default value in generic params.
Example:
type KebabCase<S, P extends string = ''> = S extends `${infer F}${infer L}`
? (F extends Lowercase<F> ? `${F}${KebabCase<L, '-'>}` : `${P}${Lowercase<F>}${KebabCase<L, '-'>}`) : S
KebabCase<'FooBarBaz'> // 'foo-bar-baz'How to test every item type in Array like some and every?
Use Array[number].
Example:
type AnyOf<T extends any[]> = T[number] extends 0 | '' | false | [] | {[key: string]: never}
? false : true;
AnyOf<[0, '', false, [], {}] //false
AnyOf<[0, '', false, [], {x: number}] //true
AnyOf<[0, '', false, [1], {}] //trueinfer match mode
type s0 =`` extends `${infer A}${infer B}${infer C}`?C:false //false
type s1 =`a` extends `${infer A}${infer B}${infer C}`?C:false //false
type s2 =`ab` extends `${infer A}${infer B}${infer C}`?C:false // ''
type s3=`abcd` extends `${infer A}${infer B}${infer C}`?C:false //'cd'
type s4=`ab_c` extends `${infer A}_${infer B}${infer C}`?C:false // ''infer as generic params
Normally, we would use infer like
type GetTypeVal1<T> = T extends { type: infer R }
? R : T extends { typeName: infer R2 } ? R2 : T
type TypeVal11 = GetTypeVal1<{ type: string }>
type TypeVal12 = GetTypeVal1<{ type: string, typeName: number }>However, one day I saw another usage of infer like this
type GetTypeVal2<T> = { type: T } | T | { typeName: T }
type TypeVal21 = { type: string } extends GetTypeVal2<infer T> ? T : any //string
type TypeVal22 = { type: string, typeName: number } extends GetTypeVal2<infer T> ? T : any //string | numberIt describes the situations first and then uses the infer as the generic params to get the matched types. A little different from GetTypeVal1. Also, we can change GetTypeVal1 to work like GetTypeVal2.
type GetTypeVal1<T> = T extends { type: infer R, typeName: infer R2 }
? R | R2 : T extends { type: infer R3 } ? R3 : T extends { typeName: infer R4 } ? R4 : T
type TypeVal11 = GetTypeVal1<{ type: string }> //string
type TypeVal12 = GetTypeVal1<{ type: string, typeName: number }> //string | numberCompared with infer in generic params, wouldn't that easier?
However, normally this is not what we want. Also, there is a related problem to look out for. microsoft/TypeScript#32389
How to add properties to an object, items to an array, or union recursively?
type TupleKeys<T extends any[], R extends number[] = []> = T extends [infer S1, ...infer S2]
? TupleKeys<S2, [S2['length'], ...R]> : R
type Index = TupleKeys<['macOS', 'Windows', 'Linux']> // [0,1,2]type TupleKeys<T extends any[]> = T extends [infer S1, ...infer S2]
? S2['length'] | TupleKeys<S2> : never
type Index = TupleKeys<['macOS', 'Windows', 'Linux']> // 0 | 2 | 1type TupleKeys<T extends any[]> = T extends [infer S1, ...infer S2]
? {
[P in `${S2['length']}`]: S2['length']
} & TupleKeys<S2> : {}
type Index= TupleKeys<['macOS', 'Windows', 'Linux']> // {2:2,1:1,0:0}Utilities
// type IsArrayEmpty<T extends []> = T["length"] extends 0 ? true : false
// type IsObjectEmpty<T extends {}> = keyof T extends never ? true : false
type IsArrayEmpty<T extends []> = T extends [] ? true : false
type IsObjectEmpty<T extends {}> = T extends { [key: string]: never } ? true : false