TypeScript的幾種類型保護方式
TypeScript 的 類型保護(Type Guards)是一種確保在代碼運行時可以更精確地處理特定類型的方法。通過類型保護,TypeScript 能夠根據特定的條件(如值的屬性或操作方式)推斷變量的類型,從而減少類型錯誤的可能性。
常見的幾種類型保護方式
- typeof 類型保護
- instanceof 類型保護
- in 操作符
- 自定義類型保護函數(Type Predicates)
- 字面量類型守護(Discriminated Unions)
1. typeof 類型保護
typeof 是 JavaScript 中的一個操作符,TypeScript 使用它來檢查基本數據類型(如 string, number, boolean)。常用于保護原始類型。
示例:
function printValue(value: string | number) {
if (typeof value === "string") {
console.log("The value is a string:", value.toUpperCase());
} else {
console.log("The value is a number:", value.toFixed(2));
}
}
printValue("Hello"); // The value is a string: HELLO
printValue(123.456); // The value is a number: 123.46
在這個例子中,typeof 通過檢查 value 是 string 還是 number 來選擇合適的操作。
2. instanceof 類型保護
instanceof 檢查某個對象是否是另一個對象的實例(即其構造函數的原型是否出現在該對象的原型鏈中)。適用于類實例的類型保護。
示例:
class Dog {
bark() {
console.log("Woof!");
}
}
class Cat {
meow() {
console.log("Meow!");
}
}
function makeSound(animal: Dog | Cat) {
if (animal instanceof Dog) {
animal.bark(); // Safe to call bark() here
} else {
animal.meow(); // Safe to call meow() here
}
}
const myDog = new Dog();
const myCat = new Cat();
makeSound(myDog); // Woof!
makeSound(myCat); // Meow!
在這個例子中,instanceof 檢查對象是否是 Dog 或 Cat 的實例,以選擇調用哪個方法。
3. in 操作符
in 操作符檢查對象中是否存在某個屬性,這對于聯合類型中可能包含不同屬性的情況非常有用。
示例:
interface Car {
drive(): void;
}
interface Boat {
sail(): void;
}
function move(vehicle: Car | Boat) {
if ("drive" in vehicle) {
vehicle.drive(); // Safe to call drive() here
} else {
vehicle.sail(); // Safe to call sail() here
}
}
const car: Car = {
drive() {
console.log("Driving the car");
},
};
const boat: Boat = {
sail() {
console.log("Sailing the boat");
},
};
move(car); // Driving the car
move(boat); // Sailing the boat
這里,in 操作符檢查 vehicle 是否有 drive 屬性,以此決定執行 drive() 或 sail()。
4. 自定義類型保護函數(Type Predicates)
通過使用 類型謂詞(Type Predicates),可以創建自定義的類型保護函數。類型謂詞的語法是:param is Type,它表明如果函數返回 true,則 param 的類型為 Type。
示例:
interface Fish {
swim(): void;
}
interface Bird {
fly(): void;
}
function isFish(animal: Fish | Bird): animal is Fish {
return (animal as Fish).swim !== undefined;
}
function moveAnimal(animal: Fish | Bird) {
if (isFish(animal)) {
animal.swim(); // TypeScript knows `animal` is a Fish
} else {
animal.fly(); // TypeScript knows `animal` is a Bird
}
}
const fish: Fish = {
swim() {
console.log("The fish is swimming");
},
};
const bird: Bird = {
fly() {
console.log("The bird is flying");
},
};
moveAnimal(fish); // The fish is swimming
moveAnimal(bird); // The bird is flying
在這個例子中,isFish 是一個自定義類型保護函數。它檢查 animal 是否為 Fish,并根據類型來調用相應的方法。
5. 字面量類型守護(Discriminated Unions)
字面量類型守護是通過在聯合類型中引入一個區分字段(discriminant field)來實現的。通常在每個類型中使用一個固定的字面量屬性來進行類型保護。
示例:
interface Square {
kind: "square";
size: number;
}
interface Rectangle {
kind: "rectangle";
width: number;
height: number;
}
interface Circle {
kind: "circle";
radius: number;
}
type Shape = Square | Rectangle | Circle;
function getArea(shape: Shape): number {
switch (shape.kind) {
case "square":
return shape.size * shape.size;
case "rectangle":
return shape.width * shape.height;
case "circle":
return Math.PI * shape.radius * shape.radius;
default:
return 0;
}
}
const square: Square = { kind: "square", size: 5 };
console.log(getArea(square)); // 25
在這個例子中,Shape 類型是由 Square, Rectangle 和 Circle 組成的聯合類型,它們都有 kind 字段,通過這個字段我們可以區分出當前的具體類型并相應處理。
總結
TypeScript 提供了多種類型保護方式來安全地處理聯合類型或復雜的類型結構:
- typeof: 用于檢查基本數據類型 (string, number, boolean)。
- instanceof: 用于檢查對象是否是某個類的實例。
- in: 用于檢查對象是否具有某個屬性。
- 自定義類型保護函數: 通過類型謂詞創建自定義的類型保護函數。
- 字面量類型守護(Discriminated Unions): 使用區分字段來區分聯合類型中的不同類型。
這些類型保護方式可以幫助你在 TypeScript 中更安全地編寫代碼,并減少運行時錯誤。