Mah*_*Ali 4 javascript typescript
考虑以下三种类型中,MainType
是工会Type1
和Type2
。如果kind
是"kind1"
那么data
应该是{msg: string}
相同的类型Type2
interface Type1 {
kind: "kind1";
data: { msg: string };
}
interface Type2 {
kind: "kind2";
data: { msg2: string };
}
type MainType = Type1 | Type2;
Run Code Online (Sandbox Code Playgroud)
这是使用它的第一种方法。
function func(obj: MainType) {
switch (obj.kind) {
case "kind1": return obj.data.msg;
case "kind2": return obj.data.msg2;
}
}
Run Code Online (Sandbox Code Playgroud)
上面的代码没有给出错误并显示正确的自动完成。
但是当我们解构obj
它时,它会出错。
function func({kind, data}: MainType) {
switch (kind) {
case "kind1": return data.msg;
case "kind2": return data.msg2;
}
}
Run Code Online (Sandbox Code Playgroud)
错误是
'msg'
类型上不存在属性'{ msg: string; } | { msg2: string; }'
也许它的一些非常基本的东西。但我是 ts 的新手,所以我无法了解解构如何改变类型。请解释原因,并告诉有什么方法可以解决它。
Mac*_*ora 10
通过在函数参数级别使用解构,我们松散了kind
和之间的联系data
。所以 switch bykind
并没有data
像现在那样缩小它们在不同数据结构中的范围。
我可以说你消除了两者之间的界限kind
,data
这意味着你真正引入了两个变量,一个是 type kind1 | kind2
,第二个是 type { msg: string; } | { msg2: string; }
。
结果我们不再有形式的判别式kind
了。
下面是解构行为的等效代码:
const f = (t: MainType) => {
const kind = t.kind // "kind1" | "kind2";
const data = t.data // {msg: string;} | {msg2: string;}
}
Run Code Online (Sandbox Code Playgroud)
是的,从逻辑角度来看,您的代码完全没问题,因为我们知道这些字段之间的关系,所以它应该可以工作。不幸的是,TS 无法理解界限。
总之- 不幸的是,除非您没有将类型缩小到联合的特定成员,否则您不能使用解构,因为它会破坏字段之间的类型关系。
我们可以考虑一些类型保护的解决方法。考虑以下示例:
const isKind1 = (kind: MainType['kind'], data: MainType['data']): data is Type1['data']
=> kind === 'kind1'
const isKind2 = (kind: MainType['kind'], data: MainType['data']): data is Type2['data']
=> kind === 'kind2'
const f = ({kind, data}: MainType) => {
if (isKind1(kind, data)) {
data // is { msg: string }
}
if (isKind2(kind, data)) {
data // is { msg2: string }
}
}
Run Code Online (Sandbox Code Playgroud)
通过使用类型保护isKind1
,isKind2
我们能够在这两个变量之间创建连接。但问题是我们不能再使用switch
了,我们还有更多的代码,以及在函数中实现的字段关系而不是类型定义,这种方法很容易出错,因为我可以在函数中做不同的关系,然后原始类型正在定义。
需要明确的是,我正在展示它是可能的,但它不值得,我建议保留原始实现而不破坏结构。
归档时间: |
|
查看次数: |
641 次 |
最近记录: |