在TS中,我们可以使用 in 、keyof 、intanceof 来进行类型保护
in
interface Admin {
name: string;
privileges: string[];
}
interface Employee {
name: string;
startDate: Date;
}
type UnknownEmployee = Employee | Admin;
function printEmployeeInformation(emp: UnknownEmployee) {
console.log("Name: " + emp.name);
if ("privileges" in emp) {
console.log("Privileges: " + emp.privileges);
}
if ("startDate" in emp) {
console.log("Start Date: " + emp.startDate);
}
}
keyof
function padLeft(value: string, padding: string | number) {
if (typeof padding === "number") {
return Array(padding + 1).join(" ") + value;
}
if (typeof padding === "string") {
return padding + value;
}
throw new Error(`Expected string or number, got '${padding}'.`);
}
instanceof
interface Padder {
getPaddingString(): string;
}
class SpaceRepeatingPadder implements Padder {
constructor(private numSpaces: number) {}
getPaddingString() {
return Array(this.numSpaces + 1).join(" ");
}
}
class StringPadder implements Padder {
constructor(private value: string) {}
getPaddingString() {
return this.value;
}
}
let padder: Padder = new SpaceRepeatingPadder(6);
if (padder instanceof SpaceRepeatingPadder) {
// padder的类型收窄为 'SpaceRepeatingPadder'
}
类型谓词 is
先来看一个简单的应用
function isNumber(x: any): x is number {
return typeof x === "number";
}
function isString(x: any): x is string {
return typeof x === "string";
}
通过 x is type 来指定x的类型 相当于调用上面的函数 如果返回为true 那么 x 类型就是number
为什么会有类型保护这个东西呢? 在js中,有时候我们去访问对象的某个属性,但是可能这个属性不存在,那么就会为undefind,有时候会不符合我们的预期。当然你可以用过配置bable配置可选链保证某个对象是有属性的(使用过angular的同学应该会比较清楚)。在TS中,我们必须明确的指定对象的哪些属性是否存在.
// 定义一个动物的接口
interface Animal {
eat:() => void
}
class Dog extends Animal {
eat(){
console.log('dog eat')
}
jump(){
console.log('jump')
}
}
// 定义一个类来使用动物
class UseAnimal {
constructor(public animal :Animal)
}
const dog = new Dog()
const dogAnimal = new UseAnimal(dog)
const { animal } = dogAnimal
此时得到的animale实例只有一个eat方法 如果想要调用上面的jump方法 就需要告诉ts animal是Dog的实例
if(animal instanceof Dog) {
animal.jump()
}
但是这个方案有个具象性,即它只对有效果。例如我们重新声明一个类
class Cat extends Animal {
eat(){
console.log('dog eat')
}
jump(){
console.log('jump')
}
}
const cat = new Cat()
const catAnimal = new UseAnimal(cat)
const { animal } = catAnimal
if(animal instanceof Dog) {
animal.jump()
}
Cat 和 Dog 是两个一样的类 但是 if(animal instanceof Dog) {animal.jump()}这个判断就会返回为false 因为cat不是dogAnimal的实例 这时候你不得不去手动的修改判断
** 因此我们可以用类型谓词 **
function isAnimal(animal:any) :anmale is Dog {
return (animal as Dog).jump !== undefined
}
// 因此上面的判断可以改写为
if(isAnimal(animal)){
animal.jump() // 这样就不会报错了
}
但是上面这种写法需要为每一种类型去写判断函数。 因此我们可以利用泛型才重新定义函数
function isAnimal<T>(toCheck:any,toCheckProperty:keyof T):toCheck is T {
return (toCheck as T)[toCheckProperty] !== undefind
}