目录
前言
在前三章中,我们介绍了 TypeScript 的基础知识、函数与对象类型。在本章中,我们将探讨更高级的类型和类型操作,包括联合类型、交叉类型、字面量类型、类型断言、类型兼容性和类型守卫等内容。通过这些高级特性,你将能够编写出更加灵活和强大的代码。
回顾
在上一章中,我们学习了以下内容:
- 函数类型:包括基本函数类型、可选参数和默认参数、剩余参数。
- 对象类型:包括基本对象类型、可选属性和只读属性。
- 类型别名和接口:包括类型别名、接口扩展。
- 类型推断和上下文类型。
正文开始
,如果觉得文章对您有帮助,请帮我三连+订阅,谢谢
💖💖💖
1. 联合类型和交叉类型
a. 联合类型
联合类型(Union Types)表示一个值可以是几种类型之一。使用竖线(|
)分隔多个类型。
let id: number | string;
id = 101;
id = "ABC123";
function printId(id: number | string) {
if (typeof id === "number") {
console.log(`ID number: ${id}`);
} else {
console.log(`ID string: ${id}`);
}
}
b. 交叉类型
交叉类型(Intersection Types)表示同时包含多个类型的特性。使用和号(&
)合并多个类型。
interface Person {
name: string;
}
interface Employee {
employeeId: number;
}
type Staff = Person & Employee;
let staffMember: Staff = {
name: "张三",
employeeId: 1234,
};
2. 字面量类型
字面量类型(Literal Types)是指使用具体的值作为类型,这些值可以是字符串、数字或布尔值。
type Direction = "Up" | "Down" | "Left" | "Right";
function move(direction: Direction) {
console.log(`Moving ${direction}`);
}
move("Up");
move("Right");
// move("Forward"); // 错误:不能将类型“"Forward"”分配给类型“Direction”
3. 类型断言
类型断言(Type Assertion)允许你告诉编译器某个值的具体类型。
let someValue: unknown = "这是一个字符串";
let strLength: number = (someValue as string).length;
console.log(`字符串长度: ${strLength}`);
4. 类型兼容性
TypeScript 的类型兼容性基于结构子类型(structural subtyping),这意味着类型的兼容性是通过它们的成员来判断的。
interface Named {
name: string;
}
let person: Named;
let animal = { name: "旺财", breed: "狗" };
person = animal; // 正确,animal 包含了 name 属性
5. 类型守卫
类型守卫(Type Guards)用于在运行时检查值的类型,以确保类型安全。
a. typeof
类型守卫
function padLeft(value: string, padding: number | string) {
if (typeof padding === "number") {
return Array(padding + 1).join(" ") + value;
}
if (typeof padding === "string") {
return padding + value;
}
throw new Error(`Expected number or string, got ${typeof padding}`);
}
console.log(padLeft("Hello", 4)); // 输出: " Hello"
console.log(padLeft("Hello", ">>> ")); // 输出: ">>> Hello"
b. instanceof
类型守卫
class Dog {
bark() {
console.log("汪汪");
}
}
class Cat {
meow() {
console.log("喵喵");
}
}
function makeSound(animal: Dog | Cat) {
if (animal instanceof Dog) {
animal.bark();
} else {
animal.meow();
}
}
let myDog = new Dog();
let myCat = new Cat();
makeSound(myDog); // 输出: 汪汪
makeSound(myCat); // 输出: 喵喵
c. 自定义类型守卫
interface Fish {
swim(): void;
}
interface Bird {
fly(): void;
}
function isFish(pet: Fish | Bird): pet is Fish {
return (pet as Fish).swim !== undefined;
}
function getPet(): Fish | Bird {
return Math.random() < 0.5 ? { swim: () => console.log("游泳") } : { fly: () => console.log("飞行") };
}
let pet = getPet();
if (isFish(pet)) {
pet.swim(); // 正确
} else {
pet.fly(); // 正确
}
扩展知识点:类型映射(Mapped Types)
类型映射(Mapped Types)是一种生成新类型的方式,通常用于转换现有类型的属性。
type Readonly<T> = {
readonly [P in keyof T]: T[P];
};
interface User {
id: number;
name: string;
}
let readonlyUser: Readonly<User> = {
id: 1,
name: "李四",
};
// readonlyUser.id = 2; // 错误,id 是只读属性
结语
通过本章的学习,你应该对 TypeScript 中的高级类型和类型操作有了更深入的理解。掌握这些高级特性将使你能够编写更加灵活和强大的代码。在下一章中,我们将继续探讨 TypeScript 中的接口和类,包括它们的定义、使用以及高级特性。务必掌握好每个概念,它们将为你后续学习 TypeScript 提供坚实的基础。