Skip to content

Type Challenge

基本原理

if else条件语句

如果要用if else语句,比如if(A <= B) true else false,可以如下写法。

type A = 1
type B = 1 | 2
type Result = A extends B ? true : false

如果要写if(A <= B) and (C <= D) ...

type A = 1
type B = 1 | 2
type C = 3
type D = 3 | 4
type Result = A extends B
  ? C extends D
    ? "true, true"
    : "true, false"
  : C extends D
    ? "false, true"
    : "false, false"

空数组

type A = []
type IsEmptyArray<Arr extends unknown[]> =
	Arr['length'] extends 0 ? true : false
type Result = IsEmptyArray<A>
//    ^-- true

非空数组

type A = [1]
type NotEmpty<Arr extends unknown[]> =
  Arr extends [...infer X, infer Last] ? true : false
type Result = NotEmpty<A>
//   ^-- true

infer相当于给unknow[]取名字

递归

最多递归数组的时候最多47层。

type A = ['ji', 'ni', 'tai', 'mei']
type Reverse<Arr extends unknown[]> =
	Arr extends [...infer Rest, infer Last]
  ? [Last, ...Reverse<Rest>]
  : Arr
type Result = Reverse<A>
// Result is ['mei', 'tai', 'ni', 'ji']

模式匹配 + infer"引用"

type Tuple = ["ji", "ni", "tai", "mei"]
type Result1 = Tuple extends [infer First, ...infer Rest]
  ? First : never
// Result1 is "ji"
type Result2 = Tuple extends [infer First, ...infer Rest]
  ? Rest : never
// Result2 is ["ni", "tai", "mei"]
type A = ['ji','ni','mei']
type R = A['length']

数组长度不限制,元祖长度有限制

元祖体操

可以使用JS的拓展操作符。

type A = [1]
type B = [...A,2]
type B = [1,2]
type C = [3,4]
type D = [...B,...C]

取元祖最后一项

type D = [1,2,3,4]
// 注意 1,2,3,4都是类型,不是值
type Last<T> = T extends [...items: unknow[], last: infer X]
  ? X : never
type E = Last<D>
// ^--- E = 4 注意这里的4是类型,不是值

取除了最后一项的元祖

type D = [1,2,3,4]
type NoLast<T> = T extends [...items: infer X, last: unknow[]]
  ? X : never
type E = NoLast<D>
// [1,2,3,4] => [1,2,3]
// [ ] => [ ]

字符串体操

CapitalizeTS原生就有,内置的,用于首字母大写intrinsic表示内置,内在。

type A = 'fang'
type B = Capitalize<A>
//   ^-- type B = "Fang"
type C = 'ji' | 'ni' | 'tai' | 'mei'
type X = Capitalize<C>
//   ^-- type X = "Ji" | "Ni" | "Tai" | "Mei"

还有其他内置的方法如Uppercase字符串大写Lowercase字符串小写Uncapitalize首字母小写

模版字符串

type A = "ji"
type B = "ni"
type C = "tai"
type D = "mei"
type X = `${A} ${B} ${C} ${D}`
// ^-- type X = "ji ni tai mei"
type A = "ji ni tai mei"
type First<T extends string> = T extends `${infer F}${string}` ? F : never
type Result = First<A>
// ^-- "j"

字符串可以转为元祖

// 字符串可以转为元祖
// 我们可以获取字符串的最后一项
type StringToTuple<T extends string> =
  T extends `${infer F}${infer R}`
  ? [F, ...StringToTuple<R>]
  : []
type LastOfTuple<T extends any[]> =
  T extends [...infer Rest, infer Last] ? L : never
type LastOfString<T extends string> = LastOfTuple<StringToTuple<T>>

关于infer引用可以用来数组拍平

type Flatten<Type> = Type extends Array<infer Item> ? Item : Type

string => 联合类型

type StringToUnion<S extends string> =
	S extends `${infer First}${infer Rest}`
  ? First | StringToUnion<Rest> : never
type Result = StringToUnion<'jinitaimei'>
// type Result = "j" | "i" | "n" | "t" | "a" | "m" | "e" | "i"
// 注意,联合类型自动去重了
type UnionToString<>

string => ['a','b','c']

type StringToTuple<S extends string> =
	S extends `${infer First}${infer Rest}`
  ? [First, StringToTuple<Rest>]: []
type Result = StringToTuple<'jinitaimei'>
// type Result = ["j" , "i" , "n" , "t" , "a" , "m" , "e" , "i"]
// 注意,联合类型自动去重了

判断是否为联合类型

// 泛型 + 联合 => 分配律
// 判断联合类型
// 只有联合类型才会有分配律
// 我们现在要判断一个类型是否是联合类型
// 如果被分配了,那么就是联合类型,
// 如果没有被分配,那么就不是联合类型
type IsUnion<A, B=A> = A extends A ?
  [B] extends [A] // 遇到联合类型一定返回false // 遇到非联合类型一定返回true
  ? false
  : true
: never
type UnionTostring<U> = IsUnion<U> extends true
  ?
  : never