TypeScript提供了一些有用的工具类型,以便于进行常见的类型转换。这些工具类型在全局可用。
长时间不用,有时候就忘记了, 每次都去官网查看比较麻烦, 特在此记录一份,便于查阅。
1、 Awaited<Type>用来获取 Promise 返回的类型
看官方的例子
type A = Awaited<Promise<string>>;// 直接得到 string 类型type A = string// 支持递归解析type B = Awaited<Promise<Promise<number>>>;type B = numbertype C = Awaited<boolean | Promise<number>>;type C = number | boolean2、 Partial<Type>将 type 类型的所有属性变为可选, 比较常用。
interface Todo { title: string; description: string;} function updateTodo(todo: Todo, fieldsToUpdate: Partial<Todo>) { return { ...todo, ...fieldsToUpdate };} const todo1 = { title: "organize desk", description: "clear clutter",}; const todo2 = updateTodo(todo1, { description: "throw out trash",});3、 Required<Type>与 Partial 相反, 将 Type 类型的所有属性转为必须有。
interface Props { a?: number; b?: string;} const obj: Props = { a: 5 };// 会报错 缺失了 b 属性const obj2: Required<Props> = { a: 5 };Property 'b' is missing in type '{ a: number; }' but required in type 'Required<Props>'.// 正确const obj2: Required<Props> = { a: 5, b: '123' };4、 Readonly<Type>将 Type 的所有属性标记为只读属性,是浅冻结。
export interface Todo { title: string; work: { content: string; status: boolean; }}const todo: Readonly<Todo> = { title: 'Delete inactive users', work: { content: '上王者', status: false, },};// 不会报错 可以修改todo.work.content = '学习TS';// 报错 属性 title 是只读的 不能修改todo.title = 'Hello';5、 Record<Keys, Type>创建一个对象类型, 对象的键是 keys 中的 key, 值是 type 类型
keys 是对象属性, 所以只能是 string number symbol 类型
const objRecord: Record<6, string> = { 6: 'xxx'};官方示例
interface CatInfo { age: number; breed: string;} type CatName = "miffy" | "boris" | "mordred"; const cats: Record<CatName, CatInfo> = { miffy: { age: 10, breed: "Persian" }, boris: { age: 5, breed: "Maine Coon" }, mordred: { age: 16, breed: "British Shorthair" },};6、 Pick<Type, Keys>从 type 中提取 keys 属性,生成一个新的类型
可以类比 lodash 中的 pick 方法,从一个对象中提取 keys 中的属性,形成一个新对象。
interface Todo { title: string; description: string; completed: boolean;}type TodoPreview = Pick<Todo, "title" | "completed">;const todo: TodoPreview = { title: "Clean room", completed: false,};7、 Omit<Type, Keys>与 Pick 相反, 从 Type 类型中移除 keys 中的属性, 剩下的形成一个新的类型。
interface Todo { title: string; description: string; completed: boolean; createdAt: number;}// 将 description 移除 生成一个新的类型type TodoPreview = Omit<Todo, "description">;const todo: TodoPreview = { title: "Clean room", completed: false, createdAt: 1615544252770,};// 移除 completed、createdAt 两项生成新的类型type TodoInfo = Omit<Todo, "completed" | "createdAt">;const todoInfo: TodoInfo = { title: "Pick up kids", description: "Kindergarten closes at 5pm",};8、 Exclude<UnionType, ExcludedMembers>从 UnionType 中 排除 ExcludedMembers 中的类型,生成新的类型。 可以理解为取差集。 注意 ExcludedMembers 描述的是一类 如果有多个符合,都会排除。
type T0 = Exclude<"a" | "b" | "c", "a">;// T0 实际的类型type T0 = "b" | "c"type T1 = Exclude<"a" | "b" | "c", "a" | "b">;// T1 实际的类型type T1 = "c"type T2 = Exclude<string | number | (() => void), Function>;// T2 实际的类型type T2 = string | number// 这里要注意 Function 描述的是一类。 T22 还是 string | numbertype T22 = Exclude<string | number | (() => void) | ((a: string) => void), Function>; type Shape = | { kind: "circle"; radius: number } | { kind: "square"; x: number } | { kind: "triangle"; x: number; y: number }; type T3 = Exclude<Shape, { kind: "circle" }>// T3 实际的类型 type T3 = { kind: "square"; x: number;} | { kind: "triangle"; x: number; y: number;}9、 Extract<Type, Union>从 Type 中取出 Union 中提供的类型且在 Type 中存在的, 形成新类型, 其实就是取交集。
type T0 = Extract<"a" | "b" | "c", "a" | "f">;// T0 实际类型 type T0 = "a"type T1 = Extract<string | number | (() => void), Function>;// T1 实际类型 type T1 = () => void type Shape = | { kind: "circle"; radius: number } | { kind: "square"; x: number } | { kind: "triangle"; x: number; y: number }; type T2 = Extract<Shape, { kind: "circle" }>// T2 实际类型type T2 = { kind: "circle"; radius: number;}10、 NonNullable<Type>从 Type 中排除 unll 和 undefined,生成新类型
type T0 = NonNullable<string | number | undefined>;// T0 实际类型type T0 = string | numbertype T1 = NonNullable<string[] | null | undefined>;// T1 实际类型type T1 = string[]11、字符串转换Uppercase<StringType> : 转为大写
Lowercase<StringType> :转为小写
Capitalize<StringType> : 首字母转大写
Uncapitalize<StringType> :首字母转小写
type T2 = Uppercase<'hello'> // "HELLO"type T3 = Lowercase<'HELLo'> // "hello"type T4 = Capitalize<'hellO'> // "HellO"type T5 = Uncapitalize<'HeLLo'> // "heLLo"12、 Parameters<Type>使用函数的参数类型生成元祖类型。
declare function f1(arg: { a: number; b: string }): void; type T0 = Parameters<() => string>;// T0 实际的类型type T0 = []type T1 = Parameters<(s: string) => void>;// T1 实际的类型type T1 = [s: string]type T2 = Parameters<<T>(arg: T) => T>;// T2 实际的类型type T2 = [arg: unknown]type T3 = Parameters<typeof f1>;// T3 实际的类型type T3 = [arg: { a: number; b: string;}]type T4 = Parameters<any>;// T4 实际的类型type T4 = unknown[]type T5 = Parameters<never>;// T5 实际的类型type T5 = nevertype T6 = Parameters<string>;Type 'string' does not satisfy the constraint '(...args: any) => any'.类型“string”不满足约束“(...args: any) => any”// T6 实际的类型type T6 = nevertype T7 = Parameters<Function>;Type 'Function' does not satisfy the constraint '(...args: any) => any'. Type 'Function' provides no match for the signature '(...args: any): any'.类型“Function”不满足约束“(...args: any) => any”。 类型“Function”提供的内容与签名“(...args: any): any”不匹配。// T7 实际的类型type T7 = never13、 ConstructorParameters<Type>使用构造函数的参数类型 生成元祖类型
type T0 = ConstructorParameters<ErrorConstructor>;// T0 实际的类型type T0 = [message?: string]type T1 = ConstructorParameters<FunctionConstructor>;// T1 实际的类型type T1 = string[] type T2 = ConstructorParameters<RegExpConstructor>;// T2 实际的类型type T2 = [pattern: string | RegExp, flags?: string]class C { constructor(a: number, b: string) {}}type T3 = ConstructorParameters<typeof C>;// T3 实际的类型type T3 = [a: number, b: string]type T4 = ConstructorParameters<any>;// T4 实际的类型type T4 = unknown[] type T5 = ConstructorParameters<Function>;Type 'Function' does not satisfy the constraint 'abstract new (...args: any) => any'. Type 'Function' provides no match for the signature 'new (...args: any): any'.类型“Function”不满足约束“abstract new (...args: any) => any”。 类型“Function”提供的内容与签名“new (...args: any): any”不匹配。// T5 实际的类型type T5 = never14、 ReturnType<Type>使用函数的返回值类型生成新的类型
declare function f1(): { a: number; b: string }; type T0 = ReturnType<() => string>;// T0 实际的类型type T0 = stringtype T1 = ReturnType<(s: string) => void>;// T1 实际的类型type T1 = voidtype T2 = ReturnType<<T>() => T>;// T2 实际的类型type T2 = unknowntype T3 = ReturnType<<T extends U, U extends number[]>() => T>;// T3 实际的类型type T3 = number[]type T4 = ReturnType<typeof f1>;// T4 实际的类型type T4 = { a: number; b: string;}type T5 = ReturnType<any>;// T5 实际的类型type T5 = anytype T6 = ReturnType<never>;// T6 实际的类型type T6 = nevertype T7 = ReturnType<string>;Type 'string' does not satisfy the constraint '(...args: any) => any'.类型“string”不满足约束“(...args: any) => any”// T7 实际的类型type T7 = anytype T8 = ReturnType<Function>;Type 'Function' does not satisfy the constraint '(...args: any) => any'. Type 'Function' provides no match for the signature '(...args: any): any'.类型“Function”不满足约束“(...args: any) => any”。 类型“Function”提供的内容与签名“(...args: any): any”不匹配。// T8 实际的类型type T8 = any15、 InstanceType<Type>使用构造函数的实例类型作为新的类型
class C { x = 0; y = 0;} type T0 = InstanceType<typeof C>;// T8 实际的类型type T0 = Ctype T1 = InstanceType<any>;// T8 实际的类型type T1 = anytype T2 = InstanceType<never>;// T8 实际的类型type T2 = nevertype T3 = InstanceType<string>;Type 'string' does not satisfy the constraint 'abstract new (...args: any) => any'.类型“string”不满足约束“abstract new (...args: any) => any”// T8 实际的类型type T3 = anytype T4 = InstanceType<Function>;Type 'Function' does not satisfy the constraint 'abstract new (...args: any) => any'. Type 'Function' provides no match for the signature 'new (...args: any): any'.类型“Function”不满足约束“abstract new (...args: any) => any”。 类型“Function”提供的内容与签名“new (...args: any): any”不匹配。// T8 实际的类型type T4 = any16、 ThisParameterType<Type>提取一个函数类型显式定义的 this 参数,如果没有显式定义的 this 参数,则返回 unknown 。 这里有如下几个需要注意的点:
this参数只能叫 this,且必须在参数列表的第一个位置this 必须是显式定义的这个 this 参数在函数实际被调用的时候不存在,不需要显式作为参数传入,而是通过 call、apply或者是 bind 等方法指定function toHex(this: Number) { return this.toString(16);} function numberToString(n: ThisParameterType<typeof toHex>) { return toHex.apply(n);}17、 OmitThisParameter<Type>官网解释:将一个定义了 this 参数类型的函数类型中的this 参数类型去掉。
查阅其它文档的理解:对于没有定义 this 参数类型的函数类型,直接返回这个函数类型,如果定义了 this 参数类型,就返回一个仅是去掉了 this 参数类型的新函数类型
function toHex(this: Number) { return this.toString(16);} const fiveToHex: OmitThisParameter<typeof toHex> = toHex.bind(5); console.log(fiveToHex());18、ThisType<Type>官网的解释是:不返回转换后的类型,只充当上下文类型的标记。
要使用 ThisType 必须保证 noImplicitThis 配置开启
type ObjectDescriptor<D, M> = { data?: D; methods?: M & ThisType<D & M>; // Type of 'this' in methods is D & M}; function makeObject<D, M>(desc: ObjectDescriptor<D, M>): D & M { let data: object = desc.data || {}; let methods: object = desc.methods || {}; return { ...data, ...methods } as D & M;} let obj = makeObject({ data: { x: 0, y: 0 }, methods: { moveBy(dx: number, dy: number) { this.x += dx; // Strongly typed this this.y += dy; // Strongly typed this }, },}); obj.x = 10;obj.y = 20;obj.moveBy(5, 5);作者:mzl_mw链接:https://juejin.cn/post/7353582927680159781