![Laucher](../avatar.jpeg)
Laucher
2022年 10月 18日
TypeScript的高级类型
在实际开发中,根据不同的场景和需求合理地运用TypeScript的这些高级类型,将会大大提升我们的代码质量和开发效率。也可以使我们编写更灵活、更安全、更通用的代码。
![封面图](/static/41eb0c0eb394aaa2dee98c153c19a94e/52292/typescript.webp)
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" };
在上面的例子中,我们定义了接口 A
和 B
,分别拥有 foo
和 bar
属性。然后我们使用交叉类型 C
将 A
和 B
合并成一个新类型,即 C
包含了 A
和 B
的所有属性。最后,我们创建一个对象 obj
,它满足 C
类型,即同时包含 foo
和 bar
属性。
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>
,如果类型 T
是 number
,则返回 string
类型,否则返回 boolean
类型。根据 result1
、result2
和 result3
的赋值情况可以看到,条件类型根据不同的类型参数返回了不同的结果类型。
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
,表示一个拥有 x
和 y
属性的对象。通过类型别名,我们可以在代码中使用 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 中的高级类型包括:
- 联合类型(Union Types):表示一个变量可以是多种类型之一。
- 交叉类型(Intersection Types):合并多个类型,包含所有类型的特性。
- 映射类型(Mapped Types):从一个现有的类型创建新的类型,通过对原类型的属性进行修改或添加。
- 条件类型(Conditional Types):根据类型判断选择不同的类型。
- 索引类型(Index Types):通过索引访问对象属性,并根据索引的类型推断出对应属性的值的类型。
- 类型别名(Type Alias):为类型定义一个别名,提高代码可读性和可维护性。
- 类型约束(Type Constraint):限制泛型类型参数的范围,使得泛型只能接受符合特定条件的类型。