【发布时间】:2022-01-20 13:10:26
【问题描述】:
我有一个Optional 类型:
export type Optional<T> =
| {
hasValue: false;
}
| {
hasValue: true;
value: T;
};
还有一个人为的泛型类型Value:
type Value<PAYLOAD> = {
value: PAYLOAD;
};
正如预期的那样,这个函数没有错误:
function workingAsExpected1(msg: Optional<string>) {
const v: Value<Optional<string>> = {
value: msg,
}
}
现在,我定义了一个 SpecialValue 泛型类型,它基本上等同于 Value 类型,但对于导致我遇到的问题是必要的:
type SpecialValue<PAYLOAD> = PAYLOAD extends undefined
? never
: Value<PAYLOAD>;
现在,当msg 在函数范围内定义时,一切都按预期工作:
function workingAsExpected2() {
const msg: Optional<string> = {
hasValue: true,
value: '',
};
const v: SpecialValue<Optional<string>> = {
value: msg,
};
}
但是当我将msg 定义为函数的参数时——具有完全相同的类型——我在v 下得到一个错误:
function notWorking(msg: Optional<string>) {
const v: SpecialValue<Optional<string>> = {
value: msg,
};
};
“'{ hasValue: false; }' 类型中缺少属性'value',但在'{ hasValue: true; value: string; }'类型中是必需的”
我在这里缺少什么?为什么SpecialValue 会导致错误,而Value 不会,当它们评估为完全相同的类型时?为什么当我在范围内定义变量时它会起作用,但当我将它定义为参数时它却不起作用,即使它们是完全相同的类型?
【问题讨论】:
-
在
workingAsExpected内部,编译器使用control flow analysis on assignment 将msg的类型缩小到const msg: { hasValue: true; value: string;},但在notWorking()的主体内部没有这样的赋值,所以它必须处理@ 987654347@ 作为完整的联合类型。你可以用任何你想要的Optional<string>调用notWorking(msg),即使hasValue是false。 -
我很乐意写一个答案,但也许您可以先edit 您的问题将代码简化为minimal reproducible example,如this?似乎
SpecialValue<T>和Value<T>并不是真正直接相关的。告诉我。 -
@jcalz 但是为什么
workingAsExpected1有效?这和notWorking之间的唯一区别是Value与SpecialValue。 -
SpecialValue<T>和Value<T>是不同的类型;前者distributes over unions inT而后者没有。{value: {hasValue: false} | {hasValue: true, value: string}}和{value: {hasValue: false}} | {value: {hasValue: true, value: string}}不被视为同一类型。如果您问的是 那个 差异,那么workingAsExpected2中发生的控制流分析可能不相关,您应该简化为 this -
有几次你说几种类型是“相同的”和“等价的”,但实际上它们不是。为了将问题保持在合理的范围内,也许您可以将自己限制在仅询问这些看似等效的类型中的一种……无论您主要关心的是哪一种。您总是可以打开多个问题。否则答案将由多个互不相关的子答案组成。
标签: typescript