我正在尝试将一个项目存储在一个对象中,其中对象键是类型的区分符。
请参见下面的修改。
这是一个简单的例子:
type Foo = {
id: 'foo'
}
type Bar = {
id: 'bar'
}
type Container = {
foo: Foo
bar: Bar
};
const container: Container = {
foo: { id: 'foo' },
bar: { id: 'bar' },
};
function storeValue(value: Foo | Bar) {
container[value.id] = value; // <= Error happens here. See below.
}
这是我得到的完整错误
TS2322: Type 'Foo | Bar' is not assignable to type 'Foo & Bar'.
Type 'Foo' is not assignable to type 'Foo & Bar'.
Type 'Foo' is not assignable to type 'Bar'.
Types of property 'id' are incompatible.
Type '"foo"' is not assignable to type '"bar"'.
我尝试过这样的事情:
type Container = {
[key in (Foo|Bar)['id']]: FooBar | undefined
}
有了这个,错误就消失了……但是随后它允许这样的事情(在container.foo中分配一个Bar):
function storeValue(value: Foo | Bar) {
container.foo = value; // OK... but it shouldn't be.
}
是否可以从key
推断类型?
type Container = {
[key in (Foo|Bar)['id']]: ??? | undefined // <= Here, infer the type based on the `key`
}
我阅读了文档,FAQ,尝试了很多事情,阅读了很多SO帖子,GitHub问题...我什么都没找到。
编辑:其他示例(仍进行了简化,但更接近于我的用例。仅供参考,我正在使用Twilio Video)
type DataPublication = {
kind: 'data';
// other props
}
type AudioPublication = {
kind: 'audio';
// other props
}
type VideoPublication = {
kind: 'video';
// other props
}
type Publication = DataPublication | AudioPublication | VideoPublication;
class Whatever {
publications: {
data: DataPublication | undefined
audio: AudioPublication | undefined
video: VideoPublication | undefined
} = {
data: undefined,
audio: undefined,
video: undefined
}
handlePublishedWorking(publication: Publication) {
switch (publication.kind) {
case 'data':
this.publications.data = publication; // publication is narrowed to DataPublication
break;
case 'audio':
this.publications.audio = publication; // publication is narrowed to AudioPublication
break;
case 'video':
this.publications.video = publication; // publication is narrowed to VideoPublication
break;
}
}
handlePublishedNotWorking(publication: Publication) {
this.publications[publication.kind] = publication;
}
}
答案 0 :(得分:1)
问题是您试图依靠运行时信息来进行区分。
TypeScript在运行时不存在。在运行时只有JavaScript。
function storeValue(value: Foo | Bar) {
container[value.id] = value;
}
TypeScript在这一行中唯一了解value.id
的信息是它可以是foo
或boo
。
它无法评估值并采用正确的类型,因为它可以更改。
因此,container[value.id]
的类型为container['foo'] | container['boo']
,
因此您看到的错误。
您需要告诉TypeScript它是哪种类型。
一种方法是通过控制流:
type Foo = {
id: 'foo'
}
type Bar = {
id: 'bar'
}
type Container = {
foo: Foo
bar: Bar
};
const container: Container = {
foo: { id: 'foo' },
bar: { id: 'bar' },
};
function storeValue(value: Foo | Bar) {
if (value.id === 'foo')
container['foo'] = value;
else
container['bar'] = value;
}
您会发现else
的TypeScript可以正确地分析出只有bar
是可能的值,从而执行正确的类型检查。