《TypeScript实战指南》—2.2.3 类型保护与区分类型
2.2.3 类型保护与区分类型
联合类型可用于把值区分为不同的类型。但当我们想确切地了解某个值的类型时该怎么办?
首先想到的肯定是类型断言。我们先来看下面这样一个例子:
interface Teacher {
teach(): void
}
interface Student {
Learn(): void
}
function getPerson(): Teacher | Student {
return {} as Teacher; // 假设我们构造了一个 teacher 或者 student
}
const person = getPerson(); // person: Teacher | Student
(<Student>person).learn();
// [ts]
// Property 'learn' does not exist on type 'Teacher | Student'.
// Property 'learn' does not exist on type 'Teacher'.
(<Teacher>person).teach();
// [ts]
// Property 'teach' does not exist on type 'Teacher | Student'.
// Property 'teach' does not exist on type 'Student'.
由于函数的返回值类型已经预设为 Teacher | Student,所以后续 person的类型也推导为 Teacher | Student。这导致我们并不能只调用交集中的函数,这是个很大的问题。
所以只能使用类型断言来强制类型推测,如下所示:
interface Teacher {
teach(): void
}
interface Student {
Learn(): void
}
function getPerson(): Teacher | Student {
return {} as Teacher; // 假设我们构造了一个 teacher 或者 student
}
const person = getPerson();
(<Student>person).learn();
(<Teacher>person).teach();
虽然我们可以顺利使用在 Student 和 Teacher 中的函数了,但每次都必须写上类型断言是一件非常麻烦的事。
所以在 TypeScript 里有一种类型保护机制,可以让代码可读性得到提升,同时还能减少使用烦琐的类型断言。
要实现类型保护,只需要简单地定义一个函数就可以,但返回值必须是一个主谓宾语句,如下所示:
function isTeacher(person: Teacher | Student): person is Teacher {
return (<Teacher>person).teach !== undefined;
}
在这个例子里,person is Teacher就是类型保护语句,说明参数必须来自于当前函数签名里的一个参数名。
每当使用一些变量调用 isTeacher 时,TypeScript会将变量指定为类型保护中的类型。但这个类型与变量的原始类型是兼容的。
完整示例如下:
interface Teacher {
teach(): void
}
interface Student {
learn(): void
}
function getPerson(): Teacher | Student {
return {} as Teacher
}
const person = getPerson();
function isTeacher(person: Teacher | Student): person is Teacher {
return (<Teacher>person).teach !== undefined;
}
if (isTeacher(person)) {
person.teach()
} else {
person.learn()
}
TypeScript 很聪明,它不仅能知道在 if 分支中的 Teacher 类型,还能推测出 else 分支中的必然是 Person类型,这都得益于类型保护的实现。
- 点赞
- 收藏
- 关注作者
评论(0)