gpt4 book ai didi

node.js - 为什么类型检查器认为这是错误的类型以及如何处理?

转载 作者:行者123 更新时间:2023-12-04 07:14:44 24 4
gpt4 key购买 nike

我有 typescript 类型检查器的问题。我定义了以下类型和类型保护:

type Result = ResultFail | ResultSuccess;

type ResultSuccess = {
data: unknown;
success: true
};

type ResultFail = {
data: Record<string, never>;
success: false;
}

const isResultFail = (subject: Result): subject is ResultFail =>
!subject.success

type A =
| ASuccess
| AFail;

type ASuccess =
ABase & {
result: ResultSuccess;
};

type AFail =
ABase & {
result: ResultFail;
};

type ABase = {
x: number;
y: number;
};
我正在尝试编写构建 A 的函数.当我这样做时,它不起作用:
const buildA = (result: Result): A => {
return {
x: 1,
y: 1,
result,
}
}
但是当我以另一种方式做它时:
const buildA = (result: Result): A => {
if (isResultFail(result)) {
return {
result,
x: 1,
y: 1,
}
}
return {
result,
x: 1,
y: 1,
}
}
有人可以向我解释为什么第一个版本不起作用,但第二个版本可以。我真的很困惑。

最佳答案

当编译器比较一个类型时 X查看是否可分配给另一种类型 Y ,遗憾的是不能花太多时间检查。如果它们具有不同的表观结构,即使每个类型为 X 的有效值也可能会拒绝赋值。也是 Y 类型的有效值.一种可能有效的分配被拒绝的情况是,当您尝试分配具有诸如 {a: string} | {a: number} 之类的属性的对象的联合时。到具有属性联合的对象,如 {a: string | number} :

declare let x: { a: string } | { a: number }
declare let y: { a: string | number };
x = y; // error
为了验证这个分配,编译器需要拆分 {a: string | number}进入 {a: string} | {a: number} .虽然这不会那么糟糕,但一般程序会非常笨拙。想象一下编译器给出了 {a: string | number | symbol, b: Date | RegExp | string[], c: 1 | 2 | 3 | 4 | 5 | 6}并且需要针对某些对象类型联合进行测试。它需要产生一个 3×3×6 = 54 个成员的联合,其他地方的类似联合将导致编译器检查的类型爆炸。
microsoft/TypeScript#12052和相关问题的更多信息,特别是 this comment在 microsoft/TypeScript#45230 上有关为什么不能这样做的权威声明。

在 TypeScript 3.5 之前,这样的赋值总是失败。但是 TypeScript 3.5 引入了对 "smarter" union type checking 的支持,在 microsoft/TypeScript#30779 中实现.现在,如果您的对象类型联合是 discriminated union并且满足其他一些条件,分配可以成功:
declare let x: { a: 0, z: 2 | 3 } | { a: 1, z: 3 | 4 }
declare let y: { a: 0 | 1, z: 3 };
x = y; // okay
这是有效的,因为 x 的类型是与 a 的歧视联合作为判别属性。 literal types 01可用于确定您所在的联合成员。因此上述赋值从 TypeScript 3.5 开始就起作用了。
所以,万岁。

对您来说不幸的是,您拥有的工会类型不是受歧视的工会。您可能的判别属性不是文字类型,而是对象类型,它本身就是一个判别联合。
declare let x: { a: { d: 0 }, z: 2 | 3 } | { a: { d: 1 }, z: 3 | 4 }
declare let y: { a: { d: 0 } | { d: 1 }, z: 3 };
x = y; // error
也就是说,您的联合类型类似于“嵌套歧视联合”。而 TypeScript 不支持这些。见 microsoft/TypeScript#18758对于要求此类支持的功能请求。
需要明确的是,这就是您要执行的操作:
declare let x:
{ result: ResultSuccess, x: number, y: number } |
{ result: ResultFail, x: number, y: number };
declare let y: { result: Result, x: number, y: number };
x = y; // error
这失败了,因为 result属性(property)不被视为歧视工会的歧视。那好吧。

您的其他方法有效,因为您使用 control flow analysis缩小我所说的范围 yx 并集的左腿或右腿,现在不需要担心联合传播:
declare let x:
{ result: ResultSuccess, x: number, y: number } |
{ result: ResultFail, x: number, y: number };
declare let y1: { result: ResultSuccess, x: number, y: number };
declare let y2: { result: ResultFail, x: number, y: number };
x = y1; // okay
x = y2; // okay
如果您接受这种方法,并且愿意为了类型安全而牺牲便利性,那太好了。否则,由于这只是 TypeScript 的设计限制,我在这里的建议可能是您使用 type assertion并继续你的生活。你比这里的编译器更了解你的代码的安全性,所以你可以这么说:
const buildA = (result: Result) => {
return {
x: 1,
y: 1,
result,
} as A; // assert here
}
Playground link to code

关于node.js - 为什么类型检查器认为这是错误的类型以及如何处理?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/68834629/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com