通过云主机建设网站,信宜做网站设置,贵阳网站建设公司,做猎头要用的网站知乎类型编程主要的目的就是对类型做各种转换#xff0c;如何对类型做修改#xff1f; TypeScript 类型系统支持 3 种可以声明任意类型的变量#xff1a; type、infer、类型参数。
type#xff1a;类型别名#xff0c;声明一个变量存储某个类型。type t Promisenumber如何对类型做修改 TypeScript 类型系统支持 3 种可以声明任意类型的变量 type、infer、类型参数。
type类型别名声明一个变量存储某个类型。type t Promisenumberinfer用于提取类型存到声明的变量里。type GetValueTypeP P extends Promiseinfer Value ? Value : never;类型参数用于接受具体类型。type isTwoT T extends 2 ? true: false;
但是上述三种’变量’不是通常我们理解的变量因为不能被重新赋值。但是做类型编程是为了能够产生各种负责的类型因此只有通过重新构造来产生新类型。
重新构造
TypeScript 的 type、infer、类型参数声明的变量都不能修改想对类型做各种变换产生新的类型就需要重新构造。
数组类型重新构造
添加类型
当我们声明了一个元组变量后需要给这个元组类型添加新类型时
//在最后添加 push
type tuple [1,2,3];type PushArr extends unknown[], Ele [...Arr, Ele];type result Push[1,2,3],4//[1,2,3,4]//在最前面添加 unshifttype UnshiftArr extends unknown[], Ele [Ele, ...Arr];type result2 Unshift[1,2,3],0复杂案例 构造要求 将已有的两个元组类型合并成一个新的元组类型
type tuple1 [1,2];
type tuple2 [hello,world];//合并后
type tuple [[1,hello],[2,world]];思路提取元组中的两个元素构造成新的元组
type ZipOne extends [unknown,unknown], Other extends [unknown,unknown] One extends [infer OenFirst, infer OneSecond] ? Other extends [infer OtherFirst, infer OtherSecond]? [[OneFirst, OtherFirst],[OneSecond, OtherSecond]] : []: [];type result Ziptuple1,tuple2//[[1,hello],[2,world]]两个类型参数 One、Other 是两个元组类型是 [unknown, unknown]代表 2 个任意类型的元素构成的元组通过 infer 分别提取 One 和 Other 的元素到 infer 声明的局部变量 OneFirst、OneSecond、OtherFirst、OtherSecond 里用提取的元素构造成新的元组返回
同理尝试一下合并任意各元素的元组使用递归的方式 type Zip2One extends unknown[], Other extends unknown[] One extends [infer OneFirst, ...infer OneRest]? Other extends [infer OtherFirst, ...infer OtherRest]? [[OneFirst,OtherFirst], ...Zip2OneRest,OtherRest] : []: [];类型参数 One、Other 声明为 unknown[]也就是元素个数任意类型任意的数组每次提取 One 和 Other 的第一个元素 OneFirst、OtherFirst剩余的放到 OneRest、OtherRest 里用 OneFirst、OtherFirst 构造成新的元组的一个元素剩余元素继续递归处理 OneRest、OtherRes
字符串类型的重新构造
思路从已有字符串类型中提取部分字符串经过一系列变换构造成新的字符串类型
CapitalizeStr 将一个字符串字面量类型的’hello’转为首字母大写的’Hello’
type CapitalizeStrStr extends string Str extends ${infer First}${infer Rest} ? ${UppercaseFirst}${Rest} : Str;type result CapitalizeStrhello声明了类型参数 Str 是要处理的字符串类型通过 extends 约束为 string通过 infer 提取出首个字符到局部变量 First提取后面的字符到局部变量 Rest使用 TypeScript 提供的内置高级类型 Uppercase 把首字母转为大写加上 Rest构造成新的字符串类型返回
CamelCase 将一个how_are_you重新构造为howAreYou
type CamelCaseStr extends string Str extends ${infer Left}_${infer Right}${infer Rest} ? ${Left}${UppercaseRight}${CamelCaseRest} : Str;类型参数 Str 是待处理的字符串类型约束为 string提取 _ 之前和之后的两个字符到 infer 声明的局部变量 Left 和 Right剩下的字符放到 Rest 里然后把右边的字符 Right 大写和 Left 构造成新的字符串剩余的字符 Rest 要继续递归的处理
DropSubStr 删除字符串中的某个子串
type DropSubStrStr extends string, SubStr extends string Str extends ${infer Prefix}${SubStr}${infer Suffix} ? DropSubStr${Prefix}${Suffix},SubStr : Str;type result DropSubStrhello,,,,,,,//hello类型参数 Str 是待处理的字符串 SubStr 是要删除的字符串都通过 extends 约束为 string 类型通过模式匹配提取 SubStr 之前和之后的字符串到 infer 声明的局部变量 Prefix、Suffix 中如果匹配那就用 Prefix、Suffix 构造成新的字符串然后继续递归删除 SubStr。直到不再匹配也就是没有 SubStr 了
函数类型的重新构造
我们可以提取函数的参数类型和返回值类型当然可以将提取出的类型做修改后再构造出一个新的函数类型。
AppendArgument 在已有的函数类型上添加一个参数
type AppendArgumentFunc extends Function, Arg Func extends (...args: infer Args) infer ReturnType ? (...args:[...Args,Arg]) ReturnType : never;type result AppendArgument(name: string) boolean,number//(args_0:string, args_1:number) boolean;类型参数 Func 是待处理的函数类型通过 extends 约束为 FunctionArg 是要添加的参数类型通过模式匹配提取参数到 infer 声明的局部变量 Args 中提取返回值到局部变量 ReturnType 中用 Args 数组添加 Arg 构造成新的参数类型结合 ReturnType 构造成新的函数类型返回
索引类型的重新构造
索引类型是聚合多个元素的类型类似于class,对象等都是索引类型对它的修改和构造新类型涉及到了映射类型的语法
type obj {name: string;age: number;gender: boolean;
}type MappingObj extends object { [Key in keyof Obj]: Obj[Key]
}Mapping 映射过程中对value做修改
type MappingObj extends object {[Key in keyof Obj]: [Obj[key],Obj[key],Obj[key]]
}type result Mapping{a:1,b:2};//{a:[1,1,1],b:[2,2,2]}UppercaseKey 对Key做修改使用as
type UppercaseKeyObj extends object {[Key in keyof Obj as UppercaseKey string] : Obj[Key]
}type result UppercaseKey{a:1,b:2}//{A:1,B:2}Record TypeScript 提供了内置的高级类型 Record 来创建索引类型
type RecordK extends string | number | symbol, T {[P in K]:T}
指定索引和值的类型分别为 K 和 T就可以创建一个对应的索引类型
将上面的类型约束修改一下约束类型参数 Obj 为 key 为 string值为任意类型的索引类型
type UppercaseKeyObj extends Recordstring, any {[Key in keyof Obj as UppercaseKey string] : Obj[Key]
}type result UppercaseKey{a:1,b:2}//{A:1,B:2}ToReadonly 索引类型的索引可以添加 readonly 的修饰符代表只读实现给索引类型添加readonly修饰符
type ToReadonlyT {readonly [Key in keyof T]: T[Key];
}通过映射类型构造了新的索引类型给索引加上了 readonly 的修饰其余的保持不变
同理也可以用相同的方式给索引类型加可选修饰符
type ToPartialT {[Key in keyof T]?: T[Key]
}ToMutable 给索引类型去掉只读修饰符
type ToMutableT {-readonly [Key in keyof T]: T[Key]
}同理去掉可选修饰符
type ToRequiredT {[Key in keyof T]-?: T[Key]
}FilterByValueType 在构造新索引类型的时候根据值的类型做过滤
type FilterByValueTypeObj extends Recordstring,any, ValueType {[Key in keyof Obj as Obj[Key] extends ValueType ? Key : never] : Obj[Key];
}interface Person{name: string;age: number;hobby: string[];
}type result FilterByValueTypePerson, string | number // {name:string; age: number;}类型参数 Obj 为要处理的索引类型通过 extends 约束为索引为 string值为任意类型的索引类型 Recordstring, any类型参数 ValueType 为要过滤出的值的类型构造新的索引类型索引为 Obj 的索引也就是 Key in keyof Obj但要做一些变换也就是 as 之后的部分如果原来索引的值 Obj[Key] 是 ValueType 类型索引依然为之前的索引 Key否则索引设置为 nevernever 的索引会在生成新的索引类型时被去掉值保持不变依然为原来索引的值也就是 Obj[Key]