likes
comments
collection
share

盘点 TypeScript 内置类型

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

盘点 TypeScript 内置类型

当开发者开始学习 TypeScript 时,了解和理解内置类型是一个重要的步骤。TypeScript 提供了一系列内置类型,这些类型可以帮助我们更好地定义和使用变量、函数和对象。

首先,TypeScript 提供了基本的原始类型,包括 numberstringbooleannullundefined。这些类型可以用来声明变量的基本数据类型。

此外,TypeScript 还提供了一些更高级的内置类型,例如 ArrayTupleEnumAnyArray类型用于定义数组,Tuple类型用于定义具有固定长度和特定类型的数组。Enum类型用于定义枚举类型,它允许我们为一组相关的常量赋予一个更友好的名称。Any类型是 TypeScript 中的顶级类型,它允许我们在编译时不进行类型检查。

TypeScript 还引入了一些更复杂的内置类型,例如 ObjectFunctionPromiseObject 类型用于描述非原始类型的变量,Function 类型用于描述函数,Promise 类型用于处理异步操作的结果。

此外,TypeScript 还提供了一些有用的内置类型,如 DateRegExpErrorDate 类型用于处理日期和时间,RegExp 类型用于处理正则表达式,Error 类型用于处理错误。

最后,TypeScript 还支持一些高级的类型操作符和类型推断,例如 unionintersectiontype assertiontype inference。这些功能使得在 TypeScript 中定义和使用复杂类型变得更加灵活和强大。

了解和熟悉这些内置类型对于编写健壮、可维护和类型安全的 TypeScript 代码至关重要。通过合理地使用这些类型,我们可以在开发过程中更好地捕获错误、提高代码质量并减少调试时间。

本文将带大家了解 TypeScript 的一些高级类型的使用以及它的实现。

Partial

Partial用于将给定类型的所有属性设置为可选。换句话说,Partial 可以创建一个新的类型,该类型具有与原始类型相同的属性,但是这些属性都是可选的。

使用 Partial 可以很方便地定义一个对象,其中的属性可以选择性地进行赋值。这对于需要根据上下文动态设置对象属性的情况非常有用,或者当你想只更新对象的一部分属性时。

下面是一个例子,演示了如何使用 Partial 类型工具:

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

function updateUser(user: Partial<User>): void {
  // 更新用户信息
  // ...
}

const user: User = {
  name: "John",
  age: 30,
  email: "john@example.com"
};

updateUser({ name: "John Doe" }); // 仅更新名称
updateUser({ age: 31, email: "john.doe@example.com" }); // 仅更新年龄和邮箱

在上面的例子中,我们定义了一个 User 接口,它具有 nameageemail 属性。然后,我们定义了一个 updateUser 函数,它接受一个 Partial<User> 类型的参数,即一个部分完成的 User 对象。

通过使用 Partial<User>,我们可以在调用 updateUser 函数时,只传递需要更新的属性,而不需要提供完整的 User 对象。这使得我们可以轻松地只更新用户的某些属性,而不必修改其他属性。

总之,Partial 类型工具是 TypeScript 中的一个有用工具,它可以帮助我们定义具有可选属性的对象类型,并在需要时方便地更新对象的部分属性。

下面我们来看看它的实现:

/**
 * Make all properties in T optional
 */
type Partial<T> = {
    [P in keyof T]?: T[P];
};
  • type Partial<T>:通过 type 关键字定义了一个泛型类型 Partial<T>,其中 T 是一个类型参数,表示待处理的类型。
  • [P in keyof T]?:使用索引类型查询操作符 keyof T 获取类型 T 的所有属性,并使用 in 关键字遍历这些属性。P 是遍历过程中的属性名,[P in keyof T] 表示在新类型中创建一个属性,属性名为 P
  • ?: T[P]:使用可选属性操作符 ? 将属性的值变为可选的。T[P] 表示在新类型中定义的属性的类型与原类型 T 对应属性的类型相同。

综合起来,Partial<T> 的作用是将类型 T 的所有属性转换为可选属性,即每个属性都可以有值或者不设置值。这个类型在实际开发中常用于对对象进行部分更新或者扩展,方便进行属性的选择性赋值。

Required

Required 用于将给定类型的所有属性设置为必需的。换句话说,Required 可以创建一个新的类型,该类型具有与原始类型相同的属性,但是这些属性都是必需的,不能省略。

使用 Required 可以很方便地定义一个对象,其中的属性必须进行赋值。这对于确保对象的完整性和类型安全非常有用。

下面是一个例子,演示了如何使用 Required 类型工具:

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

function createUser(user: Required<User>): void {
  // 创建用户
  // ...
}

createUser({ name: "John", age: 30, email: "john@example.com" }); // 完整的用户信息
createUser({ name: "John" }); // 缺少必需的属性,会报错

在上面的例子中,我们定义了一个 User 接口,它具有 nameageemail 属性,但是这些属性都是可选的,即可以省略。然后,我们定义了一个 createUser 函数,它接受一个 Required<User> 类型的参数,即一个必需的 User 对象。

通过使用 Required<User>,我们可以确保在调用 createUser 函数时,必须提供完整的 User 对象,而不能省略任何必需的属性。这有助于保证创建的用户对象具有所需的完整性和类型安全。

下面我们来看看它的实现:

/**
 * Make all properties in T required
 */
type Required<T> = {
    [P in keyof T]-?: T[P];
};
  • type Required<T>:通过 type 关键字定义了一个泛型类型 Required<T>,其中 T 是一个类型参数,表示待处理的类型。
  • [P in keyof T]-?:使用索引类型查询操作符 keyof T 获取类型 T 的所有属性,并使用 in 关键字遍历这些属性。P 是遍历过程中的属性名,[P in keyof T] 表示在新类型中创建一个属性,属性名为 P
  • -?: T[P]:使用必选属性操作符 -? 将属性的值变为必选的。T[P] 表示在新类型中定义的属性的类型与原类型 T 对应属性的类型相同。

综合起来,Required<T> 的作用是将类型 T 的所有属性转换为必选属性,即每个属性都必须有值。这个类型在实际开发中常用于对对象进行必要属性的约束,确保属性的完整性和正确性。

Readonly

Readonly用于将给定类型的所有属性设置为只读。换句话说,Readonly 可以创建一个新的类型,该类型具有与原始类型相同的属性,但是这些属性都是只读的,不能被修改。

使用 Readonly 可以很方便地定义一个只读的对象,其中的属性不能被修改。这对于确保对象的不可变性和类型安全非常有用。

下面是一个例子,演示了如何使用 Readonly 类型工具:

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

function getUser(): Readonly<User> {
  return { name: "John", age: 30, email: "john@example.com" };
}

const user: Readonly<User> = getUser();

console.log(user.name); // John
user.name = "John Doe"; // 无法修改只读属性,会报错

在上面的例子中,我们定义了一个 User 接口,它具有 nameageemail 属性,但是这些属性都是只读的,即不能被修改。然后,我们定义了一个 getUser 函数,它返回一个 Readonly<User> 类型的只读用户对象。

通过使用 Readonly<User>,我们可以确保用户对象在被赋值给变量 user 之后,其属性不能被修改。这有助于保证对象的不可变性和类型安全。

下面我们来看看它的实现:

/**
 * Make all properties in T readonly
 */
type Readonly<T> = {
    readonly [P in keyof T]: T[P];
};
  • type Readonly<T>:通过 type 关键字定义了一个泛型类型 Readonly<T>,其中 T 是一个类型参数,表示待处理的类型。
  • readonly [P in keyof T]: T[P]:使用索引类型查询操作符 keyof T 获取类型 T 的所有属性,并使用 in 关键字遍历这些属性。P 是遍历过程中的属性名,[P in keyof T] 表示在新类型中创建一个属性,属性名为 P
  • readonly:在属性名前添加 readonly 关键字,将属性的值设为只读。

综合起来,Readonly<T> 的作用是将类型 T 的所有属性转换为只读属性,即属性的值在赋值后不可修改。这个类型在实际开发中常用于对对象进行保护,防止意外的修改或者篡改属性值。

Pick

Pick 用于从给定类型中选择指定的属性,并创建一个新的类型。换句话说,Pick 可以从一个对象类型中挑选出指定的属性,创建一个新的类型,该类型只包含指定的属性。

使用 Pick 可以很方便地从一个复杂的类型中选择需要的部分,减少了不必要的冗余信息,提高了代码的可读性和灵活性。

下面是一个例子,演示了如何使用 Pick 类型工具:

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

type UserBasicInfo = Pick<User, "name" | "age">;

const user: UserBasicInfo = {
  name: "John",
  age: 30,
};

在上面的例子中,我们定义了一个 User 接口,它具有 nameageemailaddress 属性。然后,我们使用 Pick 类型工具创建了一个新的类型 UserBasicInfo,它只包含了 nameage 属性。

通过使用 Pick<User, "name" | "age">,我们从 User 类型中挑选出了 nameage 属性,创建了一个新的类型 UserBasicInfo。然后,我们可以使用 UserBasicInfo 类型来定义 user 对象,该对象只包含了 nameage 属性。

下面我们来看看它的实现:

/**
 * From T, pick a set of properties whose keys are in the union K
 */
type Pick<T, K extends keyof T> = {
    [P in K]: T[P];
};
  • type Pick<T, K extends keyof T>:通过 type 关键字定义了一个泛型类型 Pick<T, K>,其中 T 是一个类型参数,表示待处理的类型,K 是一个类型参数,表示要选取的属性的键集合,K extends keyof T 表示 K 必须是类型 T 的键集合中的一部分。
  • [P in K]: T[P]K 表示要选取的属性的键集合,使用 in 关键字遍历这些属性。P 是遍历过程中的属性名,[P in K] 表示在新类型中创建一个属性,属性名为 P,并且只包含在 K 中的属性。

综合起来,Pick<T, K> 的作用是从类型 T 中选取指定的属性,生成一个新的类型。这个类型在实际开发中常用于需要从一个大型类型中提取部分属性的情况,可以精确地选择需要的属性,避免了不必要的属性的引入。

Record

Record 用于创建一个具有指定属性类型的对象类型。Record 接受两个类型参数,第一个参数指定属性的名称,第二个参数指定属性的类型。

使用 Record 可以很方便地定义一个具有指定属性类型的对象类型,这对于创建字典、映射等数据结构非常有用。

下面是一个例子,演示了如何使用 Record 类型工具:

type Fruit = "apple" | "banana" | "orange";
type Price = number;

const fruitPrices: Record<Fruit, Price> = {
  apple: 1.5,
  banana: 0.5,
  orange: 0.8,
};

console.log(fruitPrices.apple); // 1.5
console.log(fruitPrices.banana); // 0.5
console.log(fruitPrices.orange); // 0.8

在上面的例子中,我们定义了两个类型 FruitPriceFruit 是一个联合类型,表示水果的名称,Price 是一个数值类型,表示水果的价格。

然后,我们使用 Record<Fruit, Price> 创建了一个对象类型 fruitPrices,该对象只能包含 Fruit 类型的属性,并且属性的值必须是 Price 类型。

通过使用 Record<Fruit, Price>,我们创建了一个名为 fruitPrices 的对象,它包含了苹果、香蕉和橙子三个属性,并且它们的值分别对应了它们的价格。

下面我们来看看它的实现:

/**
 * Construct a type with a set of properties K of type T
 */
type Record<K extends keyof any, T> = {
    [P in K]: T;
};
  • type Record<K extends keyof any, T>:通过 type 关键字定义了一个泛型类型 Record<K, T>,其中 K 是一个类型参数,表示要作为属性键的类型,T 是一个类型参数,表示属性值的类型。K extends keyof any 表示 K 必须是任意类型的键集合中的一部分。
  • [P in K]: T:使用索引类型查询操作符 keyof any 获取任意类型的所有键,并使用 in 关键字遍历这些键。P 是遍历过程中的键名,[P in K] 表示在新类型中创建一个属性,属性名为 P,属性值为类型 T

综合起来,Record<K, T> 的作用是创建一个新类型,其中每个属性的键都是类型 K 中的元素,并且每个属性的值都是类型 T。这个类型在实际开发中常用于需要创建具有特定键和值类型的对象的情况,可以方便地定义和操作这些对象。

Exclude

Exclude 用于从一个联合类型中排除指定的类型。

Exclude 接受两个类型参数,第一个参数是要排除的类型,第二个参数是要从中排除类型的联合类型。

下面是一个例子,演示了如何使用 Exclude 类型工具:

type Animal = "dog" | "cat" | "bird";
type ExcludeBird = Exclude<Animal, "bird">;

const myPets: ExcludeBird[] = ["dog", "cat"];

在上面的例子中,我们定义了一个联合类型 Animal,它包含了三种动物类型:dogcatbird

然后,我们使用 Exclude<Animal, "bird"> 创建了一个新的类型 ExcludeBird,该类型排除了 Animal 类型中的 bird 类型。

最后,我们定义了一个数组 myPets,它的元素类型是 ExcludeBird,即排除了 bird 类型的 Animal 类型。所以,myPets 数组只能包含 dogcat

通过使用 Exclude 类型工具,我们可以方便地从一个联合类型中排除某个特定的类型,从而创建一个新的类型,以满足特定的需求。

下面我们来看看它的实现:

/**
 * Exclude from T those types that are assignable to U
 */
type Exclude<T, U> = T extends U ? never : T;
  • type Exclude<T, U>:通过 type 关键字定义了一个泛型类型 Exclude<T, U>,其中 T 是一个类型参数,表示待处理的类型,U 是一个类型参数,表示要排除的类型。
  • T extends U ? never : T:使用条件类型来判断类型 T 是否可以赋值给类型 U。如果可以赋值,即 TU 的子类型,那么返回 never 类型,表示排除该类型。如果不可以赋值,即 T 不是 U 的子类型,那么返回 T 类型本身。

综合起来,Exclude<T, U> 的作用是从类型 T 中排除所有可以赋值给类型 U 的类型,生成一个新的类型。这个类型在实际开发中常用于需要从一个类型中排除指定类型的情况,可以过滤掉不需要的类型,提高代码的类型安全性和灵活性。

Extract

Extract 用于从一个联合类型中提取指定的类型。

Extract 接受两个类型参数,第一个参数是要提取的类型,第二个参数是要从中提取类型的联合类型。

下面是一个例子,演示了如何使用 Extract 类型工具:

type Animal = "dog" | "cat" | "bird";
type ExtractBird = Extract<Animal, "bird">;

const myBird: ExtractBird = "bird";

在上面的例子中,我们定义了一个联合类型 Animal,它包含了三种动物类型:dogcatbird

然后,我们使用 Extract<Animal, "bird"> 创建了一个新的类型 ExtractBird,该类型提取了 Animal 类型中的 bird 类型。

最后,我们定义了一个变量 myBird,它的类型是 ExtractBird,即提取了 bird 类型的 Animal 类型。所以,myBird 只能是 bird

通过使用 Extract 类型工具,我们可以方便地从一个联合类型中提取某个特定的类型,以创建一个新的类型,以满足特定的需求。

下面我们来看看它的实现:

/**
 * Extract from T those types that are assignable to U
 */
type Extract<T, U> = T extends U ? T : never;
  • type Extract<T, U>:通过 type 关键字定义了一个类型别名 Extract<T, U>,其中 TU 是类型参数,分别表示待处理的类型和要提取的类型。
  • T extends U ? T : never:这是一个条件类型,它使用了类型的条件判断。如果类型 T 可以赋值给类型 U,则返回类型 T 本身,表示要提取该类型。如果类型 T 不能赋值给类型 U,则返回 never 类型,表示不提取该类型。

这个类型别名在实际开发中常用于需要仅保留特定类型的场景,可以根据类型关系对类型进行筛选和处理,提高代码的灵活性和类型安全性。

Omit

Omit 用于从一个对象类型中排除指定的属性。

Omit 接受两个类型参数,第一个参数是要从中排除属性的对象类型,第二个参数是要排除的属性的名称。

下面是一个例子,演示了如何使用 Omit 类型工具:

type Person = {
  name: string;
  age: number;
  gender: string;
};

type OmitAge = Omit<Person, "age">;

const personWithoutAge: OmitAge = {
  name: "John",
  gender: "male"
};

在上面的例子中,我们定义了一个对象类型 Person,它有三个属性:nameagegender

然后,我们使用 Omit<Person, "age"> 创建了一个新的类型 OmitAge,该类型排除了 Person 类型中的 age 属性。

最后,我们定义了一个变量 personWithoutAge,它的类型是 OmitAge,即排除了 age 属性的 Person 类型。所以,personWithoutAge 只包含 namegender 属性。

通过使用 Omit 类型工具,我们可以方便地从一个对象类型中排除指定的属性,创建一个新的类型,以满足特定的需求。

下面我们来看看它的实现:

/**
 * Construct a type with the properties of T except for those in type K.
 */
type Omit<T, K extends keyof any> = Pick<T, Exclude<keyof T, K>>;
  • type Omit<T, K extends keyof any>:通过 type 关键字定义了一个类型别名 Omit<T, K extends keyof any>,其中 TK 是类型参数,分别表示待处理的类型和要排除的属性。
  • Pick<T, Exclude<keyof T, K>>:这是一个使用了两个类型操作符的表达式。首先,keyof T 获取类型 T 的所有属性名称组成的联合类型。然后,Exclude<keyof T, K> 从属性名称联合类型中排除掉类型 K 中指定的属性。最后,Pick<T, Exclude<keyof T, K>> 从类型 T 中选取排除指定属性后的属性来构建一个新的类型。

这个类型别名在实际开发中常用于需要从一个类型中删除特定属性的场景,可以灵活控制类型的结构和组合,提高代码的可复用性和可维护性。

NonNullable

NonNullable 用于从一个类型中排除 nullundefined

NonNullable 接受一个类型参数,该参数表示要排除 nullundefined 的类型。

下面是一个例子,演示了如何使用 NonNullable 类型工具:

type NullableString = string | null | undefined;
type NonNullableString = NonNullable<NullableString>;

const str: NonNullableString = "Hello";

在上面的例子中,我们定义了一个类型 NullableString,它是一个包含 stringnullundefined 的联合类型。

然后,我们使用 NonNullable<NullableString> 创建了一个新的类型 NonNullableString,该类型排除了 NullableString 中的 nullundefined

最后,我们定义了一个变量 str,它的类型是 NonNullableString,即排除了 nullundefinedNullableString 类型。所以,str 只能是 string 类型。

通过使用 NonNullable 类型工具,我们可以方便地从一个类型中排除 nullundefined,创建一个新的类型,以确保变量不会为 nullundefined

下面我们来看看它的实现:

/**
 * Exclude null and undefined from T
 */
type NonNullable<T> = T & {};
  • type NonNullable<T>:通过 type 关键字定义了一个类型别名 NonNullable<T>,其中 T 是类型参数,表示待处理的类型。
  • T & {}:这是一个交叉类型的表达式。交叉类型用于将多个类型合并为一个类型。在这里,T{}(空对象字面量类型)进行交叉操作,表示将类型 T 和空对象类型合并为一个新的类型。

这个类型别名在实际开发中常用于需要确保变量或属性不包含 nullundefined 的场景,可以提高代码的健壮性和类型安全性。

Parameters

Parameters<T> 是一个泛型工具类型,它用于获取函数类型 T 的参数类型。它接受一个函数类型作为参数,并返回一个元组类型,其中包含了函数的每个参数类型。

例如,假设有以下函数定义:

function greet(name: string, age: number): void {
  console.log(`Hello, ${name}! You are ${age} years old.`);
}

可以使用Parameters来获取greet函数的参数类型:

type GreetParams = Parameters<typeof greet>;
// GreetParams 的类型为 [string, number]

在这个例子中,GreetParams的类型被推断为一个元组类型,其中包含了greet函数的两个参数的类型。

下面我们来看看它的实现:

/**
 * Obtain the parameters of a function type in a tuple
 */
type Parameters<T extends (...args: any) => any> = T extends (...args: infer P) => any ? P : never;

在 TypeScript 中,infer 是一个关键字,用于在条件类型中推断类型变量。条件类型是一种在类型系统中进行条件判断的方式,它可以根据不同的条件选择不同的类型。infer 关键字可以用于条件类型中的 extends 子句中,用于推断类型变量的具体类型。

在条件类型中,通常使用infer关键字将类型变量绑定到待推断的类型上。这样,在使用条件类型时,可以通过infer关键字来提取和操作这个类型。

在这个例子中,我们定义了一个Parameters<T>条件类型,它接受一个函数类型T作为参数。通过infer关键字,我们将类型变量R绑定到函数类型的参数上。如果T是一个函数类型,那么Parameters<T>将返回R,即函数的参数类型;否则,返回never

infer关键字的使用使得我们可以在条件类型中进行类型推断,从而更加灵活地操作和处理不同类型的情况。

ConstructorParameters

ConstructorParameters 用于获取构造函数的参数类型。

ConstructorParameters 接受一个构造函数类型作为参数,并返回一个元组类型,该元组类型包含了构造函数的参数类型。

下面是一个例子,演示了如何使用 ConstructorParameters 类型工具:

class Person {
  constructor(name: string, age: number) {
    // constructor implementation
  }
}

type PersonConstructorParams = ConstructorParameters<typeof Person>;

const params: PersonConstructorParams = ["John", 25];

在上面的例子中,我们定义了一个 Person 类,它有一个构造函数,接受一个 name 参数和一个 age 参数。

然后,我们使用 ConstructorParameters<typeof Person> 创建了一个新的类型 PersonConstructorParams,该类型是一个元组类型,包含了 Person 构造函数的参数类型。

最后,我们定义了一个变量 params,它的类型是 PersonConstructorParams,即 Person 构造函数的参数类型的元组。所以,params 是一个包含 nameage 的元组。

通过使用 ConstructorParameters 类型工具,我们可以方便地获取构造函数的参数类型,并将其用于声明变量、函数参数等。

下面我们来看看它的实现:

/**
 * Obtain the parameters of a constructor function type in a tuple
 */
type ConstructorParameters<T extends abstract new (...args: any) => any> = T extends abstract new (...args: infer P) => any ? P : never;
  • type ConstructorParameters<T extends abstract new (...args: any) => any>:通过 type 关键字定义了一个类型别名 ConstructorParameters<T extends abstract new (...args: any) => any>,其中 T 是类型参数,表示待处理的抽象构造函数类型。
  • T extends abstract new (...args: infer P) => any ? P : never:这是一个条件类型的表达式。条件类型用于根据某个条件选择不同的类型。在这里,T extends abstract new (...args: infer P) => any 是一个条件,如果 T 是一个抽象构造函数类型,那么 P 将被推断为构造函数的参数类型数组。而 ? P 表示当条件成立时,返回 P,即参数类型数组;而 : never 表示当条件不成立时,返回 never 类型。

这个类型别名在实际开发中常用于需要从抽象构造函数类型中获取构造函数参数类型的场景,可以用于构造函数的参数类型的推断和使用。

ReturnType

ReturnType<T>是一个泛型工具类型,它用于获取函数类型T的返回值类型。它接受一个函数类型作为参数,并返回该函数的返回值类型。

例如,假设有以下函数定义:

function add(a: number, b: number): number {
  return a + b;
}

可以使用ReturnType来获取add函数的返回值类型:

type AddResult = ReturnType<typeof add>;
// AddResult 的类型为 number

在这个例子中,AddResult的类型被推断为add函数的返回值类型,即number类型。

下面我们来看看它的实现:

/**
 * Obtain the return type of a function type
 */
type ReturnType<T extends (...args: any) => any> = T extends (...args: any) => infer R ? R : any;

ReturnType<T>条件类型,它接受一个函数类型T作为参数。通过infer关键字,我们将类型变量R绑定到函数类型的返回值上。如果T是一个函数类型,那么ReturnType<T>将返回R,即函数的返回值类型;否则,返回never

InstanceType

InstanceType 用于获取构造函数的实例类型。

InstanceType 接受一个构造函数类型作为参数,并返回该构造函数类型的实例类型。

下面是一个例子,演示了如何使用 InstanceType 类型工具:

class Person {
  name: string;
  age: number;

  constructor(name: string, age: number) {
    this.name = name;
    this.age = age;
  }

  sayHello() {
    console.log(`Hello, my name is ${this.name} and I'm ${this.age} years old.`);
  }
}

type PersonInstance = InstanceType<typeof Person>;

const person: PersonInstance = new Person("John", 25);
person.sayHello();

在上面的例子中,我们定义了一个 Person 类,它有一个构造函数和一些实例方法。

然后,我们使用 InstanceType<typeof Person> 创建了一个新的类型 PersonInstance,该类型是 Person 构造函数的实例类型。

最后,我们定义了一个变量 person,它的类型是 PersonInstance,即 Person 构造函数的实例类型。我们通过 new Person("John", 25) 创建了一个 Person 的实例,并将其赋值给 person

通过使用 InstanceType 类型工具,我们可以方便地获取构造函数的实例类型,并将其用于声明变量、函数返回值等。

下面我们来看看它的实现:

/**
 * Obtain the return type of a constructor function type
 */
type InstanceType<T extends abstract new (...args: any) => any> = T extends abstract new (...args: any) => infer R ? R : any;
  • type InstanceType<T extends abstract new (...args: any) => any>:通过 type 关键字定义了一个类型别名 InstanceType<T extends abstract new (...args: any) => any>,其中 T 是类型参数,表示待处理的抽象构造函数类型。
  • T extends abstract new (...args: any) => infer R ? R : any:这是一个条件类型的表达式。条件类型用于根据某个条件选择不同的类型。在这里,T extends abstract new (...args: any) => infer R 是一个条件,如果 T 是一个抽象构造函数类型,那么 R 将被推断为构造函数实例的类型。而 ? R 表示当条件成立时,返回 R,即构造函数实例的类型;而 : any 表示当条件不成立时,返回 any 类型。

这个类型别名在实际开发中常用于需要从抽象构造函数类型中获取构造函数实例类型的场景,可以用于构造函数实例类型的推断和使用。

Uppercase

Uppercase 用于将字符串类型的字母转换为大写。

Uppercase 接受一个字符串类型作为参数,并返回该字符串类型的大写版本。

下面是一个例子,演示了如何使用 Uppercase 类型工具:

type UppercaseString = Uppercase<"hello">;
// UppercaseString 的类型为 "HELLO"

const str: UppercaseString = "HELLO";

在上面的例子中,我们使用 Uppercase<"hello"> 创建了一个新的类型 UppercaseString,该类型是字符串类型 "hello" 的大写版本,即 "HELLO"

然后,我们定义了一个变量 str,它的类型是 UppercaseString,即字符串类型的大写版本。我们将字符串 "HELLO" 赋值给 str

通过使用 Uppercase 类型工具,我们可以方便地将字符串类型的字母转换为大写,并将其用于类型声明。

下面我们来看看它的实现:

/**
 * Convert string literal type to uppercase
 */
type Uppercase<S extends string> = intrinsic;
  • type Uppercase<S extends string>:通过 type 关键字定义了一个类型别名 Uppercase<S extends string>,其中 S 是类型参数,表示待处理的字符串类型。
  • intrinsic:这是一个占位符,表示实际的内置类型或函数。在这里,intrinsic 代表了一个内部实现,用于将字符串类型中的字符转换为大写形式。

综合起来,Uppercase<S> 的作用是将字符串类型 S 中的字符转换为大写形式,并返回一个新的类型。

需要注意的是,这段代码中的 intrinsic 只是为了表示一个内部实现的占位符,并不是实际的代码。在实际开发中,我们可以使用 TypeScript 提供的内置类型 Uppercase<S> 来实现将字符串类型中的字符转换为大写形式的功能。

Lowercase

Lowercase 用于将字符串类型的字母转换为小写。

Lowercase 接受一个字符串类型作为参数,并返回该字符串类型的小写版本。

下面是一个例子,演示了如何使用 Lowercase 类型工具:

type LowercaseString = Lowercase<"HELLO">;
// LowercaseString 的类型为 "hello"

const str: LowercaseString = "hello";

在上面的例子中,我们使用 Lowercase<"HELLO"> 创建了一个新的类型 LowercaseString,该类型是字符串类型 "HELLO" 的小写版本,即 "hello"

然后,我们定义了一个变量 str,它的类型是 LowercaseString,即字符串类型的小写版本。我们将字符串 "hello" 赋值给 str

通过使用 Lowercase 类型工具,我们可以方便地将字符串类型的字母转换为小写,并将其用于类型声明。

下面我们来看看它的实现:

/**
 * Convert string literal type to lowercase
 */
type Lowercase<S extends string> = intrinsic;
  • type Lowercase<S extends string>:通过 type 关键字定义了一个类型别名 Lowercase<S extends string>,其中 S 是类型参数,表示待处理的字符串类型。
  • intrinsic:这是一个占位符,表示实际的内置类型或函数。在这里,intrinsic 代表了一个内部实现,用于将字符串类型中的字符转换为小写形式。

需要注意的是,这段代码中的 intrinsic 只是为了表示一个内部实现的占位符,并不是实际的代码。在实际开发中,我们可以使用 TypeScript 提供的内置类型 Lowercase<S> 来实现将字符串类型中的字符转换为小写形式的功能。

Capitalize

Capitalize 用于将字符串的第一个字符转换为大写。

例如:

type MyString = 'hello';
type CapitalizedString = Capitalize<MyString>;
// CapitalizedString 的类型为 'Hello'

在上面的例子中,我们使用 Capitalize 类型工具将字符串类型 MyString 的第一个字符转换为大写,并将结果赋值给类型别名 CapitalizedString。由于 MyString 的值是 'hello',所以 CapitalizedString 的类型为 'Hello'

需要注意的是,Capitalize 只能应用于字符串类型。如果尝试将其他类型(如数字、布尔值)应用于 Capitalize,则会得到一个编译时错误。

下面我们来看看它的实现:

/**
 * Convert first character of string literal type to uppercase
 */
type Capitalize<S extends string> = intrinsic;

Uncapitalize

Uncapitalize用于将字符串的第一个字符转换为小写。

例如:

type MyString = 'Hello';
type UncapitalizedString = Uncapitalize<MyString>;
// UncapitalizedString 的类型为 'hello'

在上面的例子中,我们使用 Uncapitalize 类型工具将字符串类型 MyString 的第一个字符转换为小写,并将结果赋值给类型别名 UncapitalizedString。由于 MyString 的值是 'Hello',所以 UncapitalizedString 的类型为 'hello'

需要注意的是,Uncapitalize 只能应用于字符串类型。如果尝试将其他类型(如数字、布尔值)应用于 Uncapitalize,则会得到一个编译时错误。

下面我们来看看它的实现:

/**
 * Convert first character of string literal type to lowercase
 */
type Uncapitalize<S extends string> = intrinsic;