C33. 类型运算
3.1. 使用 &
和 |
运算符创建新类型
类型运算符允许组合现有类型,构建更复杂的类型。
3.1.1. 联合类型(Union Types) |
语法:
Type1 | Type2
表示值可以是其中一种类型,需通过类型守卫确定具体类型。
typescript
// 示例:联合类型
let value: string | number;
value = "TypeScript"; // 合法
value = 42; // 合法
value = true; // ❌ 报错!类型不匹配
function logId(id: string | number) {
if (typeof id === "string") {
console.log(`ID是字符串: ${id}`);
} else {
console.log(`ID是数字: ${id}`);
}
}
WARNING
联合类型需用 typeof
、instanceof
或类型守卫缩小类型范围,否则无法调用特定方法(如 toUpperCase()
)。
3.1.2. 交叉类型(Intersection Types) &
语法:
Type1 & Type2
合并多个类型的属性,形成新类型。
typescript
interface Dog {
bark(): void;
}
interface Bird {
fly(): void;
}
type SuperPet = Dog & Bird;
const pet: SuperPet = {
bark() { console.log("汪!") },
fly() { console.log("飞走了!") }
};
3.2. 使用 ?
创建可选类型
在接口或类型中,用
?
标记属性为可选。
typescript
interface User {
name: string;
age?: number; // 可选属性
}
const user1: User = { name: "Alice" }; // 合法
const user2: User = { name: "Bob", age: 30 }; // 合法
const user3: User = { }; // ❌ 必须提供 name
TIP
访问可选属性时建议使用可选链操作符(?.
):
typescript
console.log(user.age?.toString()); // 若 age 不存在,返回 undefined
3.3. 泛型(Generics)
泛型允许函数、接口或类操作“任意类型”,避免重复代码。
示例:泛型函数
typescript
// 泛型函数:返回传入的值
function identity<T>(arg: T): T {
return arg;
}
const num = identity<number>(42); // 显式指定类型参数
const str = identity("Hello"); // 类型推断自动推导为 string
泛型接口
typescript
interface GenericIdentity {
<T>(arg: T): T;
}
const myIdentity: GenericIdentity = identity;
INFO
泛型参数名通常用单字母:T
(Type)、K
(Key)、U
(Type Union)等。
3.4. 使用 extends
对泛型约束
通过
extends
限制泛型参数的类型,确保其具备特定属性。
typescript
// 约束为有 length 属性的类型
function logLength<T extends { length: number }>(arg: T): number {
return arg.length;
}
logLength("TypeScript"); // 合法,返回 10
logLength([1, 2, 3]); // 合法,返回 3
logLength(42); // ❌ 报错!number 没有 length 属性
示例:约束为接口
typescript
interface HasId {
id: number;
}
function processItem<T extends HasId>(item: T): T {
item.id = 123;
return item;
}
const user = processItem({ id: 1, name: "Alice" }); // 合法
const invalid = processItem({ name: "Bob" }); // ❌ 缺少 id 属性
3.5. 基础类型体操
通过组合类型运算符和泛型,实现灵活的类型操作。
示例:提取对象的键类型
typescript
type Keys = keyof { name: string; age: number }; // "name" | "age"
示例:映射类型(基础)
typescript
type PartialUser<T> = {
[P in "name" | "age"]?: T; // 将指定属性改为可选
};
type User = PartialUser<string>; // { name?: string; age?: string }
WARNING
类型操作需遵循 TypeScript 的类型推断规则,避免因类型过于复杂导致编译错误。
知识回顾
核心要点
- 类型运算符:
|
:联合类型(值可为其中一种类型)。&
:交叉类型(合并多个类型的属性)。?
:定义可选属性。
- 泛型:
- 用
<T>
定义类型参数,实现类型复用。 extends
约束泛型参数的类型。
- 用
- 类型安全:
- 联合类型需用类型守卫缩小范围。
- 泛型约束确保参数具备必要属性。
- 类型体操:
- 使用
keyof
提取属性名,通过映射类型自定义对象结构。
- 使用
课后练习
单选题:以下哪个运算符用于创建交叉类型?
- A.
|
- B.
&
- C.
+
- D.
*
- A.
填空题:定义一个泛型函数
identity
,其类型应为<T>(arg: T) => T
,代码为:function identity____(arg: T): T { return arg; }
代码纠错:
typescriptinterface Animal { name: string; } function showName(animal: Animal | null) { return animal.name; // ❌ 报错!可能为 null }
综合题:
- 定义一个接口
Rectangle
,包含width
和height
属性。 - 使用交叉类型创建
Square
,合并Rectangle
和side: number
属性。 - 编写一个泛型函数
getLength<T extends { length: number }>(arg: T)
,返回arg.length
。 - 使用
extends
约束泛型,确保传入对象包含id
属性。
- 定义一个接口