字面量类型检查 (Literal Type Checking)[区分联合体(Discriminated Unions)]
在 TypeScript 中,字面量类型(literal types)允许你将变量的类型限制为特定的值,比如特定的字符串、数字或布尔值。这种类型的精确性增强了代码的安全性和表达力,使得编译器可以在编译时捕捉到更多潜在的错误。
type UserTextEvent = { value: string; target: HTMLInputElement };
type UserMouseEvent = { value: number; target: HTMLButtonElement };
type userEvent = UserTextEvent | UserMouseEvent;
/*
type userEvent = {
value: string | number;
target: HTMLInputElement | HTMLButtonElement;
}
// 确定value 类型后,无法判断target 类型
*/
function handle(event: userEvent) {
if (typeof event.value === "string") {
console.log(event.value); // string
console.log(event.target); // 未确定target 类型:HTMLInputElement | HTMLButtonElement
} else {
console.log(event.value);
console.log(event.target);
}
}
/**
* 通过子面量确定是_UserTextEvent 还是_UserMouseEvent
*/
type _UserTextEvent = {
type: "textEvent";
value: string;
target: HTMLInputElement;
};
type _UserMouseEvent = {
type: "mouseEvent";
value: number;
target: HTMLButtonElement;
};
type _userEvent = _UserTextEvent | _UserMouseEvent;
function _handle(event: _userEvent) {
if (event.type === "textEvent") {
console.log(event.value); // string
console.log(event.target); // 确定target 类型:HTMLInputElement | HTMLButtonElement
} else {
console.log(event.value);
console.log(event.target);
}
}定义字面量类型
你可以使用具体的字面量值来定义类型,这包括字符串字面量类型、数字字面量类型和布尔字面量类型等。下面是一些例子:
// 字符串字面量类型
type Easing = "ease-in" | "ease-out" | "ease-in-out";
// 数字字面量类型
type Quantity = 50 | 100;
// 布尔字面量类型
type BooleanLiteral = true | false;通过这种方式,你可以确保变量只能被赋予这些预定义的值之一。
使用字面量类型
当你声明一个具有字面量类型的变量时,TypeScript 编译器会强制要求该变量的值必须是其中一个字面量值。例如:
let myEasing: Easing;
myEasing = "ease-in"; // OK
myEasing = "some-other-value"; // Error: Type '"some-other-value"' is not assignable to type 'Easing'.字面量类型与联合类型
字面量类型经常与联合类型一起使用,以创建一组有限的可能值。这使得你可以定义非常具体的类型,从而提高代码的安全性和可读性。
function setCssTransition(
element: HTMLElement,
property: string,
duration: number,
easing: Easing
) {
element.style.transition = `${property} ${duration}ms ${easing}`;
}
setCssTransition(document.body, "opacity", 200, "ease-in"); // OK
setCssTransition(document.body, "opacity", 200, "linear"); // Error: Argument of type '"linear"' is not assignable to parameter of type 'Easing'.在这个例子中,setCssTransition 函数接受一个 Easing 类型的参数,它只能是 "ease-in"、"ease-out" 或 "ease-in-out" 之一。
字面量类型与控制流分析
结合 TypeScript 的控制流分析功能,字面量类型可以进一步增强类型保护的效果。例如,你可以根据字面量值的不同执行不同的逻辑分支:
function getPadding(value: string, padding: "left" | "right") {
if (padding === "left") {
return `Left padding: ${value}`;
} else {
return `Right padding: ${value}`;
}
}在这个例子中,getPadding 函数的 padding 参数只能是 "left" 或 "right"。通过条件语句,TypeScript 编译器能够准确地推断出在每个分支中 padding 的具体值,并允许你安全地执行相应的操作。
字面量类型与自定义类型守卫
字面量类型也可以与自定义类型守卫结合使用,以实现更复杂的类型缩小:
interface Circle {
kind: "circle";
radius: number;
}
interface Square {
kind: "square";
sideLength: number;
}
type Shape = Circle | Square;
function isCircle(shape: Shape): shape is Circle {
return shape.kind === "circle";
}
function getArea(shape: Shape) {
if (isCircle(shape)) {
return Math.PI * shape.radius ** 2; // shape is Circle here
} else {
return shape.sideLength ** 2; // shape is Square here
}
}在这个例子中,kind 属性是一个字面量类型,它用于区分不同的形状。通过 isCircle 自定义类型守卫,我们可以有效地缩小 shape 的类型范围,使代码更加安全和易于理解。
注意事项
严格模式:确保你的项目启用了严格的编译选项(如
strict),以便充分利用字面量类型带来的好处。性能考虑:虽然字面量类型提高了类型安全性,但在某些情况下可能会引入额外的编译开销。不过,通常这种影响是可以忽略不计的。
灵活性:虽然字面量类型提供了强大的类型约束,但也要注意不要过度使用它们,以免限制代码的灵活性。
总结
字面量类型是 TypeScript 提供的一种强大工具,它允许你将变量的类型限制为特定的值,从而提高代码的安全性和表达力。结合联合类型、控制流分析和自定义类型守卫,字面量类型可以帮助你在编写代码时充分利用 TypeScript 的静态类型检查能力。