阿里云主机折上折
  • 微信号
Current Site:Index > Built-in utility types (Partial, Required, etc.)

Built-in utility types (Partial, Required, etc.)

Author:Chuan Chen 阅读数:42263人阅读 分类: TypeScript

Built-in Utility Types (Partial, Required, etc.)

TypeScript provides a series of built-in utility types to simplify type manipulation. These utility types are based on generics and conditional types, helping developers handle type transformations and combinations more efficiently. Among them, Partial, Required, Readonly, Pick, Record, etc., are the most commonly used.

Partial

The Partial utility type makes all properties of type T optional. This is particularly useful when partial updates to an object are needed.

interface User {
  id: number;
  name: string;
  age: number;
}

type PartialUser = Partial<User>;
// Equivalent to:
// {
//   id?: number;
//   name?: string;
//   age?: number;
// }

function updateUser(id: number, changes: Partial<User>) {
  // Logic to update user
}

updateUser(1, { name: "John" }); // Only updates the name property

The implementation principle of Partial is based on mapped types:

type Partial<T> = {
  [P in keyof T]?: T[P];
};

Required

Required is the opposite of Partial. It makes all properties of type T mandatory.

interface Props {
  a?: number;
  b?: string;
}

type RequiredProps = Required<Props>;
// Equivalent to:
// {
//   a: number;
//   b: string;
// }

const obj1: Props = { a: 5 }; // Correct
const obj2: RequiredProps = { a: 5 }; // Error: Missing property 'b'

The implementation principle of Required:

type Required<T> = {
  [P in keyof T]-?: T[P];
};

Readonly

The Readonly utility type makes all properties of type T read-only.

interface Todo {
  title: string;
}

const todo: Readonly<Todo> = {
  title: "Learn TypeScript",
};

todo.title = "Learn JavaScript"; // Error: Cannot assign to 'title' because it is a read-only property

The implementation principle of Readonly:

type Readonly<T> = {
  readonly [P in keyof T]: T[P];
};

Pick

The Pick utility type constructs a new type by selecting a set of properties K from type T.

interface User {
  id: number;
  name: string;
  age: number;
  email: string;
}

type UserBasicInfo = Pick<User, "id" | "name">;
// Equivalent to:
// {
//   id: number;
//   name: string;
// }

const userBasic: UserBasicInfo = {
  id: 1,
  name: "John",
};

The implementation principle of Pick:

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

Record

The Record utility type constructs a type with property keys of type K and property values of type T.

type PageInfo = {
  title: string;
};

type Page = "home" | "about" | "contact";

const nav: Record<Page, PageInfo> = {
  home: { title: "Home" },
  about: { title: "About" },
  contact: { title: "Contact" },
};

The implementation principle of Record:

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

Exclude

The Exclude utility type excludes from T those types that are assignable to U.

type T0 = Exclude<"a" | "b" | "c", "a">; // "b" | "c"
type T1 = Exclude<string | number | (() => void), Function>; // string | number

The implementation principle of Exclude:

type Exclude<T, U> = T extends U ? never : T;

Extract

The Extract utility type extracts from T those types that are assignable to U.

type T0 = Extract<"a" | "b" | "c", "a" | "f">; // "a"
type T1 = Extract<string | number | (() => void), Function>; // () => void

The implementation principle of Extract:

type Extract<T, U> = T extends U ? T : never;

Omit

The Omit utility type constructs a type by removing property K from type T.

interface User {
  id: number;
  name: string;
  age: number;
  email: string;
}

type UserWithoutEmail = Omit<User, "email">;
// Equivalent to:
// {
//   id: number;
//   name: string;
//   age: number;
// }

The implementation principle of Omit:

type Omit<T, K extends keyof any> = Pick<T, Exclude<keyof T, K>>;

NonNullable

The NonNullable utility type excludes null and undefined from type T.

type T0 = NonNullable<string | number | undefined>; // string | number
type T1 = NonNullable<string[] | null | undefined>; // string[]

The implementation principle of NonNullable:

type NonNullable<T> = T extends null | undefined ? never : T;

Parameters

The Parameters utility type constructs a tuple type from the parameter types of function type T.

declare function f1(arg: { a: number; b: string }): void;

type T0 = Parameters<() => string>; // []
type T1 = Parameters<(s: string) => void>; // [s: string]
type T2 = Parameters<<T>(arg: T) => T>; // [arg: unknown]
type T3 = Parameters<typeof f1>; // [arg: { a: number; b: string }]

The implementation principle of Parameters:

type Parameters<T extends (...args: any) => any> = T extends (...args: infer P) => any ? P : never;

ReturnType

The ReturnType utility type obtains the return type of function type T.

declare function f1(): { a: number; b: string };

type T0 = ReturnType<() => string>; // string
type T1 = ReturnType<(s: string) => void>; // void
type T2 = ReturnType<<T>() => T>; // unknown
type T3 = ReturnType<<T extends U, U extends number[]>() => T>; // number[]
type T4 = ReturnType<typeof f1>; // { a: number; b: string }

The implementation principle of ReturnType:

type ReturnType<T extends (...args: any) => any> = T extends (...args: any) => infer R ? R : any;

InstanceType

The InstanceType utility type obtains the instance type of a constructor function type.

class C {
  x = 0;
  y = 0;
}

type T0 = InstanceType<typeof C>; // C
type T1 = InstanceType<any>; // any
type T2 = InstanceType<never>; // never
type T3 = InstanceType<string>; // Error

The implementation principle of InstanceType:

type InstanceType<T extends new (...args: any) => any> = T extends new (...args: any) => infer R ? R : any;

ThisParameterType

The ThisParameterType utility type extracts the type of the this parameter of a function type.

function toHex(this: Number) {
  return this.toString(16);
}

type T0 = ThisParameterType<typeof toHex>; // Number
type T1 = ThisParameterType<(this: Window, name: string) => void>; // Window
type T2 = ThisParameterType<(name: string) => void>; // unknown

The implementation principle of ThisParameterType:

type ThisParameterType<T> = T extends (this: infer U, ...args: any[]) => any ? U : unknown;

OmitThisParameter

The OmitThisParameter utility type removes the this parameter from a function type.

function toHex(this: Number) {
  return this.toString(16);
}

type T0 = OmitThisParameter<typeof toHex>; // () => string
type T1 = OmitThisParameter<(this: Window, name: string) => void>; // (name: string) => void

The implementation principle of OmitThisParameter:

type OmitThisParameter<T> = unknown extends ThisParameterType<T> ? T : T extends (...args: infer A) => infer R ? (...args: A) => R : T;

ConstructorParameters

The ConstructorParameters utility type extracts the parameter types of a constructor function type.

type T0 = ConstructorParameters<ErrorConstructor>; // [message?: string]
type T1 = ConstructorParameters<FunctionConstructor>; // string[]
type T2 = ConstructorParameters<RegExpConstructor>; // [pattern: string | RegExp, flags?: string]

The implementation principle of ConstructorParameters:

type ConstructorParameters<T extends new (...args: any) => any> = T extends new (...args: infer P) => any ? P : never;

Advanced Combination Usage

These utility types can be combined to create more complex type manipulations.

interface User {
  id: number;
  name: string;
  age: number;
  email: string;
  address?: {
    street: string;
    city: string;
  };
}

// Create a read-only, partially updatable user type
type ReadonlyPartialUser = Readonly<Partial<User>>;

// Create a type with only certain fields and mandatory
type RequiredUserFields = Required<Pick<User, "id" | "name">>;

// Create a type excluding certain fields
type UserWithoutPrivateInfo = Omit<User, "email" | "address">;

// Create a deep Partial type
type DeepPartial<T> = {
  [P in keyof T]?: T[P] extends object ? DeepPartial<T[P]> : T[P];
};

type DeepPartialUser = DeepPartial<User>;
// Equivalent to:
// {
//   id?: number;
//   name?: string;
//   age?: number;
//   email?: string;
//   address?: {
//     street?: string;
//     city?: string;
//   };
// }

Custom Utility Types

In addition to built-in utility types, developers can create their own.

// Create a Nullable type
type Nullable<T> = T | null;

// Create a Promise return type
type PromiseReturnType<T> = T extends Promise<infer R> ? R : T;

// Create an array element type
type ArrayElement<ArrayType extends readonly unknown[]> = 
  ArrayType extends readonly (infer ElementType)[] ? ElementType : never;

// Create a function parameter type
type FunctionParams<T> = T extends (...args: infer P) => any ? P : never;

// Create a type that merges two types
type Merge<A, B> = {
  [K in keyof A | keyof B]: 
    K extends keyof B ? B[K] :
    K extends keyof A ? A[K] :
    never;
};

本站部分内容来自互联网,一切版权均归源网站或源作者所有。

如果侵犯了你的权益请来信告知我们删除。邮箱:cc@cccx.cn

上一篇:映射类型基础

下一篇:自定义工具类型

Front End Chuan

Front End Chuan, Chen Chuan's Code Teahouse 🍵, specializing in exorcising all kinds of stubborn bugs 💻. Daily serving baldness-warning-level development insights 🛠️, with a bonus of one-liners that'll make you laugh for ten years 🐟. Occasionally drops pixel-perfect romance brewed in a coffee cup ☕.