ts类型体操笔记


type Test<K extends string> = K extends K ? `loop ${K}` : never
type t = Test<'A' | 'B' | 'C'>



// 
type A = {
    name: string
    age: number
}

type B = {
    age: number
    sex: string
    score: number
}

type keys = keyof (A | B) // "age"
type keyss = keyof(A & B) // "name" | "age" | "sex" | "score"

// 
type RequiredByKeys<T, K extends keyof T = keyof T> = IntersectionObj<{
  [P in keyof T as P extends K ? P : never]-?: T[P]
} & {
  [P in keyof Omit<T, K>]+?: T[P]
}>

type Mutable<T> = {
  - readonly [P in keyof T]: T[P]
}

['1', '2'][number] // '1' | '2'

type ObjectToUnion<T> = T[keyof T]

[K in F & string]: ...

type Fibonacci<
  T extends number, 
  No extends 1[] = [1, 1, 1],
  N_1 extends 1[] = [1],
  N_2 extends 1[] = [1]
> = 
  T extends 1 | 2 ? 
  1 : 
  T extends No['length'] ? 
    [...N_1, ...N_2]['length'] : 
    Fibonacci<
      T,
      [...No, 1],
      N_2,
      [...N_1, ...N_2]
    >


type Zip<A extends any[], B extends any[], L extends any[] = []> = L['length'] extends A['length'] | B['length']
  ? L
  : Zip<A, B, [...L, [A[L['length']], B[L['length']]]]>
type Zip<T, U, N extends any[] = []> = T extends [infer TF, ...infer TR] ? U extends [infer UF, ...infer UR] ? [[TF, UF], ...Zip<TR, UR>] : N : N

第一种解法很巧妙,利用 L 数组的长度来标记当前对 A 和 B 的递归位置,当 L 长度等于 A 或 B 长度时,停止遍历,返回 L 数组。随着递归的进行,每次成功的递归都会使得 L 数组的长度增加 1,而这个 +1 后的 L[‘length’] 恰好可以用在下一次递归时作为索引来获取 A 和 B 的对应元素。

第二种解法是利用递归的思想,先判断 T 和 U 是否可以被拆分成第一个元素和其他剩余部分,如果 T 和 U 都可以,则将两个取出的第一个元素组成新的元组,并递归处理剩余部分 N;如果 T 或 U 不能被拆分,则直接返回上次递归传入的当前的 N 数组


Exact number extends number ? true : false // true number extends number ? true : false // true number extends Exact number ? true : false // false


TODO

why?

type TrimRight<S extends string> = S extends `${infer Left}${infer Right}` ? Right extends ' ' | '\n' | '\t' ? TrimRight<Left> : S : S;

上面的答案是错误的,应该是下面这样的:

type TrimRight<S extends string> = S extends `${infer Left}${' ' | '\n' | '\t'}` ? TrimRight<Left> : S;

目前没能理解为什么会这样