使用 Typescript 声明了一个类型,但 Javascript 在内部使用了错误的类型

Declared a type with Typescript but Javascript internally works with a wrong type

我是 Typescript 的新手,正在观看教育视频。昨天我发现了一个奇怪的行为,并认为这是一个错误。 示例:

const json = '{"x": 10, "y":10}';
const coordinates: { x: number; y: number } = JSON.parse(json);

console.log(typeof coordinates.y);

这通常会输出 x 和 y 作为类型编号。但这不是因为类型声明,而是因为 JSON 值。 如果您将其中一个声明为字符串,VS Code 会将其视为字符串,但在内部它仍然是一个数字:

const json = '{"x": 10, "y":10}';
const coordinates: { x: number; y: string } = JSON.parse(json);

console.log(typeof coordinates.y);

这是代码:

如你所见,VS Code 将其视为字符串

但是类型检查证明这是不正确的。

在我看来,解析后的 Object/Array 具有任何类型是有道理的。但如果解析的 JSON-value 与您的注释不同,它应该向您发送错误消息,或者它应该将给定值精确地变形为注释。

我对此很陌生,所以如果我的假设有误,请告诉我!

Typescript 在编译 之前和期间进行推理。编译成 JS 后,如果你的某些代码的类型逻辑不健全,你声明的某些类型可能是无效的。这就是这里发生的事情。

JSON.parse returns any 类型的东西,可以是字面上的任何东西。您可以尝试使用以下行从中提取属性:

const coordinates: { x: number; y: string } = JSON.parse(json);

但这并不意味着解析后的对象实际上会有 x 属性 作为数字,或 y 属性 作为字符串 - 您的代码告诉编译器 假设 它确实如此,并在代码后面将 y 视为字符串。

如果你有一些东西,默认,类型any,当从它提取属性时,你应该确保它的属性确实是您指定的类型。如果您不能 100% 确定属性将始终符合预期(例如,如果输入字符串来自网络响应 - 如果响应是 503 怎么办?),请进行类型保护,例如:

const isCoordinates = (param: unknown): param is { x: number, y: number } => {
    return typeof param === 'object' && param !== null && 'x' in param;
};

然后在尝试从字符串中提取属性之前调用 isCoordinates 以确保它是您首先期望的格式。

否则,就像这里发生的那样,你可以告诉编译器一些东西 false,结果可能会出现错误和奇怪的事情。

您可以考虑启用 tslint 规则 no-unsafe-any 以避免犯此类错误。