重新构造做变换

数组类型的重新构造

向数组后面添加元素

type Push<Arr extends unknown[], Ele> = [...Arr, Ele];
type arr = Push<[1,2,3],4>;

向数组前面添加元素

type Shift<Ele, Arr extends unknown[]> = [Ele,...Arr];
type arr = Shift<1,[2,3,4]>;

合并只有两个元素的两个元组对应的元素

//合并前
type tuple1 = [1,2];
type tuple2 = ['guang', 'dong'];
//合并后
type tuple = [[1, 'guang'], [2, 'dong']];
type Zip<One extends [unknown,unknown],Other extends [unknown,unknown]> = 
One extends [infer OneFirst, infer OneSecond] ?
  Other extends [infer OtherFirst, infer OthrtSecond] ?
    [[OneFirst, OtherFirst],[OneSecond, OthrtSecond]]
  : []
: []
type zip = Zip<[1,2],['guang','dong']>;

合并只有任意个元素的两个元组对应的元素

type Zip<One extends unknown[],Other extends unknown[]> = 
One extends [infer OneFirst, ...infer OneRest] ?
  Other extends [infer OtherFirst, ...infer OthrtRest] ?
    [[OneFirst, OtherFirst],...Zip<OneRest, OthrtRest>]
  : []
: []
type zip = Zip<[1,2,3,4],['a','b','c','d']>;

字符串的重新构造

将字符串第一个元素转换成大写

type CapitalizeStrb<Str extends string> =
Str extends `${infer First}${infer Rest}` ?
  `${Uppercase<First>}${Rest}`
: Str
type str = CapitalizeStrb<'abc'>;

删除字符串中的某个字串

type DropSubStr<Str extends string, SubStr extends string> =
Str extends `${infer Prefix}${SubStr}${infer Suffix}`?
  DropSubStr<`${Prefix}${Suffix}`,SubStr>
:Str
type str = DropSubStr<'12121212121','1'>;

函数类型的重新构造

在函数类型上添加一个参数

type AppendArgument<Func extends Function, Arg> = 
Func extends (...args: infer Args)=>infer ResultType ?
  (...args: [...Args, Arg])=>ResultType
:never
type fu = AppendArgument<()=>string,number>;

索引类型重新构造

把索引类型的Key变成大写

type UppercaseKey<Obj extends Object> = {
  [Key in keyof Obj as Uppercase<Key & string>]:Obj[Key]
}
type obj = UppercaseKey<{
  name: string
}>

Record

typescript内置了Record,用来创建索引类型。

type Record<K extends keyof any, T> = {
    [P in K]: T;
};

我们可以使用Record修改上面将Key变成大写的代码

type UppercaseKey<Obj extends Record<string,any>> = {
  [Key in keyof Obj as Uppercase<Key & string>]:Obj[Key]
}
type obj = UppercaseKey<{
  name: string
}>

将索引转换成只读

type ToReadonly<T> = {
  readonly [Key in keyof T]: T[Key];
}
type obj = ToReadonly<{
  name: '1'
}>;

给索引添加可选修饰符

type ToPartial<T> = {
  readonly [Key in keyof T]?: T[Key];
}
type obj = ToPartial<{
  name: '1'
}>;

去掉只读修饰符

type ToMutable<T> = {
  -readonly [Key in keyof T]: T[Key];
}
type obj = ToMutable<{
  readonly name: '1'
}>;

去掉可选修饰符

type ToRequired<T> = {
  [Key in keyof T]-?: T[Key];
}
type obj = ToRequired<{
  name?: '1'
}>;

对索引类型做过滤

type FilterByValueType<Obj extends Record<string,any>,valueType> = {
  [Key in keyof Obj as Obj[Key] extends valueType ? Key : never] : Obj[Key];
}
type obj = FilterByValueType<{
  name: string
  un: undefined
  nu: number
},undefined|number>;

参考资料

[1]TypeScript 类型体操通关秘籍