类型保护: 当使用联合类型时, 我们必须尽量把当前值的类型收窄为当前值的实际类型,类型保护就是可执行运行时检查的一种表达式,用于确保此类型在一定范围内。
实现类型保护的四种方式:
- in 关键字
interface Dog {
name: string;
bark: () => void;
}
interface Bird {
name: string;
fly: () => void;
}
type Animal = Dog | Bird;
let animal: Animal = {
name: 'little bird',
fly: () => {
console.log('fly')
}
}
if('fly' in animal) {
animal.fly();
}
- typeof 关键字
let height: string | number;
function setHeight(height: string | number) {
if(typeof height === 'number') {
return `${height}px`;
}
if(typeof height === 'string') {
return height;
}
}
- instanceof 关键字
interface Person {
major: () =>void;
}
class Teacher implements Person {
constructor(private studying: string) {}
major() {
console.log(`student study ${this.studying}`)
}
}
class Student implements Person {
constructor(private teaches: string) {}
major() {
console.log(`teacher teaches ${this.teaches}`)
}
}
let person: Person = new Teacher('math');
if(person instanceof Teacher) {
// 收窄类型为 Teacher
console.log(true)
}
- 自定义类型保护的类型谓词 (type predicate)
function isNumber(x: any): x is number {
return typeof x === 'number'
}
interface User {
type: 'user';
name: string;
age: number;
occupation: string;
}
interface Admin {
type: 'admin';
name: string;
age: number;
role: string;
}
export type Person = User | Admin;
export const persons: Person[] = [
{ type: 'user', name: 'Max Mustermann', age: 25, occupation: 'Chimney sweep' },
{ type: 'admin', name: 'Jane Doe', age: 32, role: 'Administrator' },
{ type: 'user', name: 'Kate Müller', age: 23, occupation: 'Astronaut' },
{ type: 'admin', name: 'Bruce Willis', age: 64, role: 'World saver' }
];
export function isAdmin(person: Person): person is Admin {
return person.type === 'admin';
}
export function isUser(person: Person): person is User {
return person.type === 'user';
}
export function logPerson(person: Person) {
let additionalInformation: string = '';
if (isAdmin(person)) {
additionalInformation = person.role;
}
if (isUser(person)) {
additionalInformation = person.occupation;
}
console.log(` - ${person.name}, ${person.age}, ${additionalInformation}`);
}
console.log('Admins:');
persons.filter(isAdmin).forEach(logPerson);
console.log();
console.log('Users:');
persons.filter(isUser).forEach(logPerson);