likes
comments
collection
share

TS提供的一些实用工具类型

作者站长头像
站长
· 阅读数 4

TypeScript提供了几种有用的工具类型,以便于进行常见的类型转换。这些工具类型在全局可用。

长时间不用,有时候就忘记了, 每次都去官网查看比较麻烦, 特在此记录一份,便于查阅。

Awaited<Type>

用来获取 Promise 返回的类型

看官方的例子

type A = Awaited<Promise<string>>;
// 直接得到 string 类型
type A = string

// 支持递归解析
type B = Awaited<Promise<Promise<number>>>;
type B = number

type C = Awaited<boolean | Promise<number>>;
type C = number | boolean

Partial<Type>

将 type 类型的所有属性变为可选, 比较常用。

TS提供的一些实用工具类型

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",
});

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' };

Readonly<Type>

将 Type 的所有属性标记为只读属性

interface Todo {
  title: string;
}
const todo: Readonly<Todo> = {
  title: "Delete inactive users",
};

// 报错 属性 title 是只读的 不能修改
todo.title = "Hello";

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" },
};

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,
};

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",
};

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 | number
type 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;
}

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;
}

NonNullable<Type>

从 Type 中排除 unll 和 undefined,生成新类型

type T0 = NonNullable<string | number | undefined>;
// T0 实际类型
type T0 = string | number

type T1 = NonNullable<string[] | null | undefined>;
// T1 实际类型
type T1 = string[]

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 = never

type T6 = Parameters<string>;
Type 'string' does not satisfy the constraint '(...args: any) => any'.
类型“string”不满足约束“(...args: any) => any”
// T6 实际的类型
type T6 = never

type 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 = never

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 = never