logo
Laucher

Laucher

Laucher

2022年 10月 18日

0

TypeScript的高级类型

在实际开发中,根据不同的场景和需求合理地运用TypeScript的这些高级类型,将会大大提升我们的代码质量和开发效率。也可以使我们编写更灵活、更安全、更通用的代码。

封面图

1. 联合类型(Union Types)

联合类型用 | 符号表示,表示一个变量可以是多种类型之一。这在参数或返回值可以是多种类型的情况下非常有用。

function formatInput(input: string | number): string {
  return String(input);
}

上述例子中的 formatInput 函数接受一个参数 input,它可以是 string 类型或 number 类型。使用联合类型,函数内部可以安全地将输入转换为字符串,因为无论输入是字符串还是数字,最终都会得到正确的输出。

2. 交叉类型(Intersection Types)

交叉类型用 & 符号表示,表示一个新类型包含多个原始类型的所有属性。

interface A {
  foo: number;
}

interface B {
  bar: string;
}

type C = A & B;

const obj: C = { foo: 42, bar: "Hello" };

在上面的例子中,我们定义了接口 AB,分别拥有 foobar 属性。然后我们使用交叉类型 CAB 合并成一个新类型,即 C 包含了 AB 的所有属性。最后,我们创建一个对象 obj,它满足 C 类型,即同时包含 foobar 属性。

3. 映射类型(Mapped Types)

映射类型可以用来从一个已有的类型创建一个新的类型,通过对原类型的属性进行修改或添加。

interface Person {
  name: string;
  age: number;
}

type ReadonlyPerson = Readonly<Person>;
// 等价于
// type ReadonlyPerson = {
//   readonly name: string;
//   readonly age: number;
// };

上述例子中,我们使用 Readonly<Person> 来创建一个新类型 ReadonlyPerson,它是 Person 的只读版本,所有属性都被设为只读。

4. 条件类型(Conditional Types)

条件类型用于根据类型判断来选择不同的类型。通过 extends 关键字和三元运算符 ?: 来实现。

type MyType<T> = T extends number ? string : boolean;

let result1: MyType<number> = "hello"; // Error: 类型“string”的参数不能赋给类型“boolean”的参数
let result2: MyType<number> = true;   // Error: 类型“boolean”的参数不能赋给类型“string”的参数
let result3: MyType<number> = false;  // OK

在上面的例子中,我们定义了一个条件类型 MyType<T>,如果类型 Tnumber,则返回 string 类型,否则返回 boolean 类型。根据 result1result2result3 的赋值情况可以看到,条件类型根据不同的类型参数返回了不同的结果类型。

5. 索引类型(Index Types)

索引类型用于通过索引访问对象的属性,并根据索引的类型推断出对应属性的值的类型。

interface Person {
  name: string;
  age: number;
}

type PersonKeys = keyof Person; // "name" | "age"

let key: PersonKeys = "name";
let person: Person = { name: "Alice", age: 30 };
let value: Person[typeof key]; // string

上述例子中,keyof Person 获得了 Person 类型的所有属性名,然后通过 Person[typeof key] 推断出 person 对象中 key 属性的值的类型。

6. 类型别名(Type Alias)

类型别名用于为一个类型定义一个别名,可以将复杂类型命名为更简洁的名称,提高代码可读性和可维护性。

type Point = {
  x: number;
  y: number;
};

let p: Point = { x: 1, y: 2 };

在上面的例子中,我们使用 type 关键字定义了一个类型别名 Point,表示一个拥有 xy 属性的对象。通过类型别名,我们可以在代码中使用 Point 来表示这种类型的对象,使得代码更加清晰。

7. 类型约束(Type Constraint)

类型约束用于限制泛型类型参数的范围,使得泛型只能接受符合特定条件的类型。

function printLength<T extends { length: number }>(arg: T): void {
  console.log(arg.length);
}

在上面的例子中,我们定义了一个泛型函数 printLength,使用 extends 关键字对类型参数 T 进行约束,要求 T 必须包含一个 length 属性,且该属性的类型必须是 number。这样,我们可以在函数内部安全地访问 arg.length 属性。

printLength("Hello"); // 输出:5
printLength([1, 2, 3, 4, 5]); // 输出:5
printLength({ length: 10 }); // 输出:10

需要注意的是,类型约束使得泛型更具有通用性和类型安全性,可以适用于更多的场景。

总结归纳

TypeScript 中的高级类型包括:

  1. 联合类型(Union Types):表示一个变量可以是多种类型之一。
  2. 交叉类型(Intersection Types):合并多个类型,包含所有类型的特性。
  3. 映射类型(Mapped Types):从一个现有的类型创建新的类型,通过对原类型的属性进行修改或添加。
  4. 条件类型(Conditional Types):根据类型判断选择不同的类型。
  5. 索引类型(Index Types):通过索引访问对象属性,并根据索引的类型推断出对应属性的值的类型。
  6. 类型别名(Type Alias):为类型定义一个别名,提高代码可读性和可维护性。
  7. 类型约束(Type Constraint):限制泛型类型参数的范围,使得泛型只能接受符合特定条件的类型。

评论