在 TypeScript 中,交叉类型和联合类型是两种不同的类型。
交叉类型使用 &
符号将多个类型合并成一个新的类型。它表示一个对象必须同时具备所合并的多个类型的特性。换句话说,交叉类型可以被看作是多个类型的并集,要同时满足多个类型的要求。例如:
type A = { name: string };
type B = { age: number };
type C = A & B;
let person: C = { name: "Alice", age: 20 };
上面的代码中,类型 C
是类型 A
和类型 B
的交叉类型,它要求一个对象必须既有 name
属性又有 age
属性。
而联合类型使用 |
符号将多个类型定义在一起。它表示一个对象可以是多个类型中的任意一种类型。换句话说,联合类型可以被看作是多个类型的交集,满足其中一个类型即可。例如:
type D = A | B;
let person: D = { name: "Bob" };
person = { age: 30 };
上面的代码中,类型 D
是类型 A
和类型 B
的联合类型,它允许一个对象只有 name
属性或者只有 age
属性。
总结来说,交叉类型要求对象具备多个类型的特性,联合类型允许对象具备多个类型中的任意一种特性。你可以根据具体的需求选择使用交叉类型还是联合类型。
条件类型是 TypeScript 中的一种高级类型,它允许根据条件选择不同的类型。
条件类型的语法为 T extends U ? X : Y
,其中 T
是待检查的类型,U
是要判断的类型,X
和 Y
是根据条件选择的类型。
条件类型可以用于很多场景,下面是几个常见的应用举例:
类型过滤:可以根据某个条件过滤出类型中的符合条件的部分类型。比如,我们可以使用 Exclude
来从类型 T
中排除掉可以分配给类型 U
的部分。这对于实现高级的类型过滤很有用。
类型映射:可以根据某个条件映射类型中的部分成员类型。比如,我们可以使用 ReturnType
来获取函数类型的返回值类型。这对于实现高级的类型映射很有用。
类型推导:可以根据某个条件推断出类型中的其他部分类型。比如,在某些场景下,可以根据函数参数的类型来推断出函数返回值的类型。
条件类型是 TypeScript 中强大的工具,可以用于提供更精确和灵活的类型声明,同时也可以实现一些高级的类型操作和模式。这些特性使得 TypeScript 在静态类型检查领域有着很大的优势。
条件类型(Conditional Types)是 TypeScript 中的一个高级类型特性,它允许我们根据条件选择不同的类型。
条件类型的语法形式为 T extends U ? X : Y
,其中 T
是待检查的类型,U
是要进行检查的条件,X
是满足条件时的返回类型,Y
是不满足条件时的返回类型。
下面是一个例子,演示了如何使用条件类型:
type IsString<T> = T extends string ? true : false;
type A = IsString<"hello">; // true
type B = IsString<42>; // false
上面的例子中,我们定义了一个条件类型 IsString
,它判断传入的类型是否为 string
类型,如果是则返回 true
,否则返回 false
。通过 IsString<"hello">
和 IsString<42>
的调用,我们可以得到相应的结果。
条件类型的应用非常广泛,可以用于类型的过滤、映射和推导等场景。它可以根据不同的条件在类型层面进行判断和操作,使我们能够编写更灵活和健壮的类型逻辑。例如,在函数类型中根据参数类型的不同来进行不同的处理。
不过要注意,条件类型的嵌套和复杂使用可能会导致类型系统的复杂性增加,如果使用不当可能会造成编译时的性能问题。因此,在使用条件类型时需要谨慎考虑其复杂性和性能影响。
映射类型是 TypeScript 中的一种高级类型,它可以根据一个已知的类型,创建一个新的类型。
映射类型的语法为 { [K in Keys]: NewType }
,其中 K
是一个类型变量,Keys
是一个已知类型的属性名集合,NewType
是根据每个属性名生成的新类型。
映射类型可以用于很多场景,下面是几个常见的应用举例:
可选属性:可以通过映射类型将一个类型中的所有属性变为可选属性。比如,可以使用 { [K in keyof T]?: T[K] }
来将类型 T
中的所有属性变为可选属性。
只读属性:可以通过映射类型将一个类型中的所有属性变为只读属性。比如,可以使用 { readonly [K in keyof T]: T[K] }
来将类型 T
中的所有属性变为只读属性。
属性过滤:可以通过映射类型将一个类型中的部分属性排除掉。比如,可以使用 { [K in keyof T & U]: T[K] }
来从类型 T
中排除掉在类型 U
中定义的属性。
映射类型的灵活性使得它可以用于很多场景,可以根据实际需求来创建新的类型。它是 TypeScript 中非常有用的工具之一,可以提高代码的可读性和灵活性。
下面是几个使用映射类型的 TypeScript 代码案例:
interface Person {
name: string;
age: number;
email: string;
}
type OptionalPerson = { [K in keyof Person]?: Person[K] };
// 使用可选属性类型
const optionalPerson: OptionalPerson = {
name: "John",
age: 25
};
interface Person {
name: string;
age: number;
email: string;
}
type ReadonlyPerson = { readonly [K in keyof Person]: Person[K] };
// 使用只读属性类型
const readonlyPerson: ReadonlyPerson = {
name: "John",
age: 25,
email: "[email protected]"
};
// 下面的代码会报错,因为属性是只读的
readonlyPerson.name = "Jane";
interface Person {
name: string;
age: number;
email: string;
}
type FilteredPerson<U> = { [K in keyof Person & U]: Person[K] };
// 使用属性过滤类型
type AgeEmailPerson = FilteredPerson<"age" | "email">;
// 只包含 age 和 email 属性
const filteredPerson: AgeEmailPerson = {
age: 25,
email: "[email protected]"
};
通过这些例子,您可以更好地理解映射类型的用法和灵活性。您可以根据实际需求使用映射类型来创建新的类型,并提高代码的灵活性和可读性。
可辨识联合(Discriminated Unions)是 TypeScript
中一种用于建模具有共同属性的一组相关类型的技术。它是一种结合联合类型和字面量类型的方法
,通过一个共同的属性来区分不同的类型。
这个共同的属性一般被称为“标签”或“标识符”,它的值必须是字面量类型。通过使用可辨识联合,我们可以在类型系统中轻松识别出某个实例属于哪个具体类型,并进行相应的处理。
下面是一个简单的代码案例,使用可辨识联合来表示不同的形状:
interface Circle {
kind: "circle";
radius: number;
}
interface Square {
kind: "square";
sideLength: number;
}
interface Triangle {
kind: "triangle";
base: number;
height: number;
}
type Shape = Circle | Square | Triangle;
function calculateArea(shape: Shape): number {
switch (shape.kind) {
case "circle":
return Math.PI * shape.radius ** 2;
case "square":
return shape.sideLength ** 2;
case "triangle":
return (shape.base * shape.height) / 2;
}
}
const circle: Circle = {
kind: "circle",
radius: 5
};
console.log(calculateArea(circle)); // 输出: 78.53981633974483
在上面的代码中,我们定义了 Circle
、Square
和 Triangle
这三个接口,它们都有一个 kind
属性作为标签来区分不同的形状。然后使用 Shape
类型作为可辨识联合类型来表示这些形状。
在 calculateArea
函数中,我们使用了 switch
语句来根据 shape.kind
的值来执行不同的计算逻辑。通过可辨识联合,我们可以在编译时就确定 shape
的具体类型,并在相应的分支中进行类型安全的操作。
最后,我们创建了一个 circle
实例,并将其传递给 calculateArea
函数来计算圆的面积。根据可辨识联合的特性,编译器能够推断出 circle
的类型为 Circle
,从而执行正确的计算逻辑。
可辨识联合可以在很多场景中发挥作用,如处理不同的消息类型、实现状态机等。它是 TypeScript 中一项非常有用的高级类型技术。
keyof
操作符用于获取类型的所有可索引属性的键的联合类型。它可以与泛型结合使用,以在编译时动态获取类型的键。
例如,考虑以下示例代码:
interface Person {
name: string;
age: number;
address: string;
}
type PersonKeys = keyof Person; // "name" | "age" | "address"
function getProperty<T, K extends keyof T>(obj: T, key: K) {
return obj[key];
}
const person: Person = {
name: "John",
age: 30,
address: "123 Main St"
};
const name = getProperty(person, "name"); // 类型为 string
const age = getProperty(person, "age"); // 类型为 number
const address = getProperty(person, "address"); // 类型为 string
const invalidKey = getProperty(person, "invalid"); // 编译时错误:无效的属性键
console.log(name, age, address);
typeof
操作符用于获取表达式的类型。它在以下两种情况下特别有用:
const person = {
name: "John",
age: 30,
address: "123 Main St"
};
type PersonType = typeof person; // { name: string; age: number; address: string; }
function getPropertyValue(obj: typeof person, key: keyof typeof person) {
return obj[key];
}
const name = getPropertyValue(person, "name"); // 类型为 string
const age = getPropertyValue(person, "age"); // 类型为 number
const address = getPropertyValue(person, "address"); // 类型为 string
const invalidKey = getPropertyValue(person, "invalid"); // 编译时错误:无效的属性键
console.log(name, age, address);
TypeScript中的Partial、Required和Readonly是几个非常有用的工具类型,它们允许您在编写类型时进行更灵活的操作。
示例代码:
interface User {
name: string;
age: number;
address: string;
}
const partialUser: Partial<User> = {
name: "John",
age: 25
};
在上面的示例中,Partial
将User类型的所有属性设置为可选。所以,partialUser包含了一个部分属性的User对象。
示例代码:
interface User {
name?: string;
age?: number;
address?: string;
}
const requiredUser: Required<User> = {
name: "John",
age: 25,
address: "123 Street"
};
在上面的示例中,Required
将User类型的所有属性设置为必填项。所以,requiredUser包含了一个包含所有必填属性的User对象。
示例代码:
interface User {
name: string;
age: number;
}
const readOnlyUser: Readonly<User> = {
name: "John",
age: 25
};
// 尝试修改只读属性会引发类型错误
readOnlyUser.name = "Jane"; // Error: Cannot assign to 'name' because it is a read-only property
在上面的示例中,Readonly
将User类型的所有属性设置为只读。所以,readOnlyUser是一个只包含只读属性的User对象。
通过使用这些工具类型,可以灵活地创建更具体的类型,以适应需求,并提供更好的代码可读性和开发经验。
索引类型(Index Types)是 TypeScript 中的一种高级类型,可以用于动态地访问和操作对象中的属性。它们允许我们使用类型变量来表示对象属性的名称,并根据这些属性名称来操作对象。
有三种主要的索引类型可在 TypeScript 中使用:keyof
、typeof
和 Indexed Access Types
。
keyof
:keyof
是一个索引类型查询操作符,用于获取对象类型的所有属性名称组成的联合类型。例如:interface Person {
name: string;
age: number;
}
type PersonKeys = keyof Person; // 'name' | 'age'
typeof
:typeof
是一个类型查询操作符,用于获取变量的类型。它经常与 keyof
一起使用,可以用于获取对象类型的属性名称组成的联合类型。例如:const person = { name: 'Alice', age: 30 };
type PersonKeys = keyof typeof person; // 'name' | 'age'
interface Person {
name: string;
age: number;
}
type PersonName = Person['name']; // string
这些索引类型允许我们在编写 TypeScript 代码时更灵活地操作对象的属性,并根据需要检查、访问或操作这些属性。