为什么';t Typescript允许使用整个优化类型吗?
我希望以下截取的代码可以编译,但事实并非如此:为什么';t Typescript允许使用整个优化类型吗?,typescript,Typescript,我希望以下截取的代码可以编译,但事实并非如此: function f1(x: "A") {} function f2(x: {member: "A"}) {} let x: {member: "A" | "B"} = {member: "A"} if (x.member == "A") { f1(x.member) // compiles f2(x) // doesn't compile } 我想知道这是为什么 请注意,我正在使用strict选项进行编译 我的使用案例是,我想
function f1(x: "A") {}
function f2(x: {member: "A"}) {}
let x: {member: "A" | "B"} = {member: "A"}
if (x.member == "A") {
f1(x.member) // compiles
f2(x) // doesn't compile
}
我想知道这是为什么
请注意,我正在使用strict
选项进行编译
我的使用案例是,我想为不可变类型编写一个类型安全更新程序函数,我发现它比我目前看到的更符合人体工程学
type Update1 = <Value,
K1 extends keyof Value>
(value: Value, k1: K1, replacement: Value[K1]) => Value;
type Update2 = <Value,
K1 extends keyof Value,
K2 extends keyof Value[K1]>
(value: Value, k1: K1, k2: K2, replacement: Value[K1][K2]) => Value;
type Update3 = <Value,
K1 extends keyof Value,
K2 extends keyof Value[K1],
K3 extends keyof Value[K1][K2]>
(value: Value, k1: K1, k2: K2, k3: K3, replacement: Value[K1][K2][K3]) => Value;
// ...
type Update = Update1 & Update2 & Update3; // ...
let update: Update = (...args: Array<any>) => {
throw "to be implemented..."
};
但当涉及到狭窄的类型时,它不起作用:
if (data.value2.kind == "A") {
data.value2.aValue // compiles, can access aValues
data = update(data, "value2", "aValue", 42) // doesn't compile, not expected!
}
我认为它不起作用,因为typescript没有对类型参数值
使用缩小的类型。当我手动提供它时,我不能像在第一个示例中那样为它分配数据
,我不能用x
调用f2
- 这种行为是故意的吗?若有,原因为何
- 是虫子吗
- 有解决办法吗
- 您在这里使用的功能是。从描述此功能的页面:
判别属性类型保护是一个表达式,其形式为x.p==v,x.p==v,x.p!=v、 或x.p!==v、 其中p和v是字符串文字类型或字符串文字类型的并集的属性和表达式。鉴别属性类型保护将x的类型缩小为具有鉴别属性p和可能值v之一的x的组成类型
因此,在您的第一个示例中,问题是
x
不是联合类型,因此没有可缩小x
范围的成分。然而,这将如预期的那样起作用:
let x: {member: "A" } | {member: "B"} = {member: "A"}
if (x.member == "A") {
f1(x.member) // compiles
f2(x) // works now !
}
将此逻辑应用到更复杂的示例中,数据必须是一个联合体,以便有可能缩小到联合体的一个组成部分,因此人们可能认为这是可行的:
interface DataA {
value1: number
value2: {
kind: "A",
aValue: number,
abValue: number
}
}
interface DataB {
value1: number
value2: {
kind: "B",
bValue: number,
abValue: number
}
}
let data: DataA | DataB = undefined as any // dummy value
if (data.value2.kind == "A") {
data.value2.aValue // compiles, can access aValues
data = update(data, "value2", "aValue", 42) // doesn't compile, not expected!
}
然而,上面的代码不起作用,关于嵌套的歧视联合,这个开放的代码建议扩展类型缩小的工作方式,以涵盖这一点
唯一的解决办法是使用自定义类型的防护装置:
function isDataA(data: DataA | DataB) : data is DataA {
return data.value2.kind == "A";
}
if (isDataA(data)) {
data.value2.aValue // compiles, can access aValues
data = update(data, "value2", "aValue", 42) // compiles
}
您可能还对以下哪种解释感兴趣:
{member:“A”|“B”}
与{member:“A”}{member:“B”}
是的,看起来我在缩小问题范围时做错了什么。
function isDataA(data: DataA | DataB) : data is DataA {
return data.value2.kind == "A";
}
if (isDataA(data)) {
data.value2.aValue // compiles, can access aValues
data = update(data, "value2", "aValue", 42) // compiles
}