Appearance
TypeScript 高级类型
在掌握了 TypeScript 的基础类型后,本章节将介绍 TypeScript 的高级类型,这些类型可以帮助你构建更复杂、更灵活的类型系统。
联合类型
联合类型表示一个值可以是几种类型中的一种,使用 | 符号分隔不同的类型。
示例:
typescript
// 联合类型:字符串或数字
let value: string | number;
value = "Hello";
value = 42;
// 联合类型:布尔或字符串数组
let result: boolean | string[];
result = true;
result = ["a", "b", "c"];
// 联合类型的使用
function printValue(value: string | number): void {
if (typeof value === "string") {
console.log(`String: ${value}`);
} else {
console.log(`Number: ${value}`);
}
}
printValue("Hello"); // String: Hello
printValue(42); // Number: 42交叉类型
交叉类型表示一个值同时具有多种类型的特性,使用 & 符号连接不同的类型。
示例:
typescript
// 定义两个接口
interface Person {
name: string;
age: number;
}
interface Employee {
employeeId: number;
department: string;
}
// 交叉类型:同时具有 Person 和 Employee 的特性
type Staff = Person & Employee;
// 使用交叉类型
const staff: Staff = {
name: "John",
age: 30,
employeeId: 12345,
department: "IT"
};
console.log(staff.name); // John
console.log(staff.employeeId); // 12345类型别名
类型别名允许你为一个类型定义一个新的名称,使用 type 关键字。
示例:
typescript
// 为基本类型创建别名
type StringOrNumber = string | number;
// 使用类型别名
let value: StringOrNumber;
value = "Hello";
value = 42;
// 为对象类型创建别名
type User = {
id: number;
name: string;
email: string;
};
// 使用类型别名
const user: User = {
id: 1,
name: "John",
email: "john@example.com"
};
// 为函数类型创建别名
type AddFunction = (a: number, b: number) => number;
// 使用类型别名
const add: AddFunction = (a, b) => a + b;
console.log(add(1, 2)); // 3字面量类型
字面量类型表示一个具体的值,而不是一个类型范围。
示例:
typescript
// 字符串字面量类型
type Direction = "up" | "down" | "left" | "right";
let direction: Direction;
direction = "up"; // 正确
direction = "down"; // 正确
// direction = "north"; // 错误:Type '"north"' is not assignable to type 'Direction'
// 数字字面量类型
type DiceRoll = 1 | 2 | 3 | 4 | 5 | 6;
let roll: DiceRoll;
roll = 3; // 正确
// roll = 7; // 错误:Type '7' is not assignable to type 'DiceRoll'
// 布尔字面量类型
type BooleanLiteral = true | false;
let isActive: BooleanLiteral;
isActive = true; // 正确
// isActive = "true"; // 错误:Type '"true"' is not assignable to type 'BooleanLiteral'可选类型
可选类型表示一个属性或参数是可选的,使用 ? 符号标记。
示例:
typescript
// 可选属性
interface User {
id: number;
name: string;
email?: string; // 可选属性
age?: number; // 可选属性
}
// 创建用户对象,可以不提供可选属性
const user1: User = {
id: 1,
name: "John"
};
// 也可以提供可选属性
const user2: User = {
id: 2,
name: "Jane",
email: "jane@example.com",
age: 25
};
// 可选参数
function greet(name: string, greeting?: string): string {
if (greeting) {
return `${greeting}, ${name}!`;
}
return `Hello, ${name}!`;
}
greet("John"); // Hello, John!
greet("John", "Hi"); // Hi, John!非空断言
非空断言用于告诉 TypeScript 编译器,一个值不是 null 或 undefined,使用 ! 符号。
示例:
typescript
// 非空断言
let element: HTMLElement | null = document.getElementById("myElement");
// 告诉编译器 element 不是 null
let length: number = element!.textContent!.length;
// 非空断言在函数返回值中的使用
function getElement(id: string): HTMLElement | null {
return document.getElementById(id);
}
// 告诉编译器返回值不是 null
let myElement: HTMLElement = getElement("myElement")!;注意: 非空断言是一个编译时特性,它不会在运行时进行检查。如果实际值是 null 或 undefined,运行时仍然会报错。因此,使用非空断言时要确保值确实不是 null 或 undefined。
unknown 类型
unknown 类型是 TypeScript 3.0 引入的一种安全的 any 类型,它表示一个未知类型的值。与 any 不同,unknown 类型的值不能直接使用,需要进行类型检查或类型断言。
示例:
typescript
// unknown 类型
let unknownValue: unknown;
unknownValue = 42;
unknownValue = "Hello";
unknownValue = true;
// unknown 类型的值不能直接使用
// let length: number = unknownValue.length; // 错误:Object is of type 'unknown'
// 需要进行类型检查
if (typeof unknownValue === "string") {
let length: number = unknownValue.length; // 正确
console.log(length);
}
// 或者使用类型断言
let stringValue = unknownValue as string;
let length: number = stringValue.length; // 正确类型守卫
类型守卫是一种运行时检查,用于确定一个值的类型,以便在类型安全的情况下使用它。
typeof 类型守卫
typescript
function processValue(value: string | number): void {
if (typeof value === "string") {
// 在这里,value 被推断为 string 类型
console.log(`String length: ${value.length}`);
} else {
// 在这里,value 被推断为 number 类型
console.log(`Number value: ${value.toFixed(2)}`);
}
}
processValue("Hello"); // String length: 5
processValue(42); // Number value: 42.00instanceof 类型守卫
typescript
class Animal {
name: string;
constructor(name: string) {
this.name = name;
}
}
class Dog extends Animal {
bark(): void {
console.log("Woof!");
}
}
class Cat extends Animal {
meow(): void {
console.log("Meow!");
}
}
function makeSound(animal: Animal): void {
if (animal instanceof Dog) {
// 在这里,animal 被推断为 Dog 类型
animal.bark();
} else if (animal instanceof Cat) {
// 在这里,animal 被推断为 Cat 类型
animal.meow();
} else {
console.log(`Animal ${animal.name} makes a sound`);
}
}
const dog = new Dog("Rex");
const cat = new Cat("Whiskers");
const animal = new Animal("Generic");
makeSound(dog); // Woof!
makeSound(cat); // Meow!
makeSound(animal); // Animal Generic makes a sound自定义类型守卫
typescript
interface User {
id: number;
name: string;
email: string;
}
interface Admin {
id: number;
name: string;
role: string;
}
// 自定义类型守卫
function isAdmin(user: User | Admin): user is Admin {
return "role" in user;
}
function processUser(user: User | Admin): void {
if (isAdmin(user)) {
// 在这里,user 被推断为 Admin 类型
console.log(`Admin ${user.name} has role ${user.role}`);
} else {
// 在这里,user 被推断为 User 类型
console.log(`User ${user.name} has email ${user.email}`);
}
}
const user: User = {
id: 1,
name: "John",
email: "john@example.com"
};
const admin: Admin = {
id: 2,
name: "Jane",
role: "admin"
};
processUser(user); // User John has email john@example.com
processUser(admin); // Admin Jane has role admin实战:使用高级类型
示例 1:使用联合类型和类型守卫
typescript
// 定义联合类型
type PaymentMethod = "credit card" | "paypal" | "bank transfer";
// 定义支付信息接口
interface PaymentInfo {
method: PaymentMethod;
amount: number;
// 不同支付方式的特定属性
cardNumber?: string;
paypalEmail?: string;
bankAccount?: string;
}
// 处理支付
function processPayment(payment: PaymentInfo): void {
console.log(`Processing payment of $${payment.amount} via ${payment.method}`);
// 使用类型守卫检查支付方式
switch (payment.method) {
case "credit card":
if (payment.cardNumber) {
console.log(`Card number: ${payment.cardNumber}`);
}
break;
case "paypal":
if (payment.paypalEmail) {
console.log(`PayPal email: ${payment.paypalEmail}`);
}
break;
case "bank transfer":
if (payment.bankAccount) {
console.log(`Bank account: ${payment.bankAccount}`);
}
break;
}
}
// 使用
const creditCardPayment: PaymentInfo = {
method: "credit card",
amount: 100,
cardNumber: "1234-5678-9012-3456"
};
const paypalPayment: PaymentInfo = {
method: "paypal",
amount: 50,
paypalEmail: "user@example.com"
};
processPayment(creditCardPayment);
processPayment(paypalPayment);示例 2:使用交叉类型和类型别名
typescript
// 定义基础用户类型
type BaseUser = {
id: number;
name: string;
email: string;
};
// 定义角色类型
type Role = "user" | "admin" | "moderator";
// 定义用户类型,使用交叉类型
type UserWithRole = BaseUser & {
role: Role;
lastLogin: Date;
};
// 定义管理员类型,使用交叉类型
type AdminUser = UserWithRole & {
permissions: string[];
department: string;
};
// 使用
const user: UserWithRole = {
id: 1,
name: "John",
email: "john@example.com",
role: "user",
lastLogin: new Date()
};
const admin: AdminUser = {
id: 2,
name: "Jane",
email: "jane@example.com",
role: "admin",
lastLogin: new Date(),
permissions: ["manage users", "manage content"],
department: "IT"
};
console.log(user.name); // John
console.log(admin.permissions); // ["manage users", "manage content"]小结
本章节介绍了 TypeScript 的高级类型,包括:
- 联合类型
string | number - 交叉类型
type A = B & C - 类型别名
type - 字面量类型
- 可选类型
? - 非空断言
! - unknown 类型(安全版 any)
- 类型守卫(typeof、instanceof、自定义类型守卫)
这些高级类型可以帮助你构建更复杂、更灵活的类型系统,提高代码的类型安全性和可维护性。在实际开发中,应该根据具体需求选择合适的类型,以充分利用 TypeScript 的类型系统优势。
