首页 > 解决方案 > Typescript - 文字类型推断 - 与字符串和数字不同的行为

问题描述

根据TypeScript Literal Types,我们可以在类型位置引用特定的字符串和数字。所以以下是有效的。

function printText(s: string, alignment: "left" | "right") {
  // ...
}
printText("Hello, world", "left");  // This works
printText("G'day, mate", "centre"); // This gives error - Argument of type '"centre"' is not assignable to parameter of type '"left" | "right"'.

但是,这不适用于使用对象初始化变量时,因为 TypeScript 假定该对象的属性稍后可能会更改值。解决方法是添加类型断言(在任一位置 - 更改 1 和更改 2)。

例如

// Change 1:
const req = { url: "https://example.com", method: "GET" as "GET" };
// Change 2
handleRequest(req.url, req.method as "GET");

以上将起作用。但是如果我尝试在方法属性中插入一些不同的字符串,这些也会被认为是有效的。虽然如果我添加一个数字就不会。例如

function handleRequest(url: string, method: "GET"|"POST"):void{
console.log(method);
}

const req = { url: "https://example.com", method: "GET" };
handleRequest(req.url, req.method as "POST"); // This is accepted and works

const req1 = { url: "https://example.com", method: "ABCD" };
handleRequest(req1.url, req1.method as "GET"); // This is accepted and works

const req2 = { url: "https://example.com", method: 2 };
handleRequest(req2.url, req2.method as "GET"); // This throws an error - Conversion of type 'number' to type '"GET"' may be a mistake because neither type sufficiently overlaps with the other.

TypeScript 在与数字比较时能够正确编译,但在涉及其他字符串时不能正确编译?

标签: typescript

解决方案


类型断言是一种告诉 typescript 不要检查你的工作的方法。如果使用不当,可能会引入错误。由于这种导致错误的可能性,即使您进行类型断言,typescript 也会进行一些最少的检查,如果它发现您断言的类型与计算的类型大不相同,它会给您一个类型错误。

因此,当您尝试断言通用字符串是特定字符串时,打字稿会认为“是的,这已经足够接近了,我会按照他们的要求去做”。但是当你试图断言一个数字是一个字符串时,打字稿会说“哇,这没有意义。你确定吗?”。如果你真的确定,那么你可以通过这样做来永久关闭打字稿,在你的情况下,req2.method as unknown as "GET"

PS:更安全的选择是使用as const. 这告诉打字稿假设值不会改变,否则要准确使用它在代码中看到的内容。例如:

const req = { url: "https://example.com", method: "GET" } as const;
handleRequest(req.url, req.method); // This is accepted and works

const req1 = { url: "https://example.com", method: "ABCD" } as const;
handleRequest(req1.url, req1.method); // This correctly throws an error

const req2 = { url: "https://example.com", method: 2 } as const;
handleRequest(req2.url, req2.method); // This correctly throws an error

或者,给它一个显式类型并完全跳过对断言的需求。

const req1: { url: string, method: 'GET' | 'POST' } = {
  url: "https://example.com",
  method: "ABCD", // Error here
}

推荐阅读