我正在定义一个需要接受string
和object
类型的数组。 object
类型必须包含两个属性:name
和value
。 value
必须是另一个对象,其中包含任意一组key: value
对。
我正在尝试使用可区分的并集定义某些object
类型,以便已知某些特定value
的{{1}}的属性。但是,始终需要保留一个后备,以便在name
不是已知的字符串文字时,name
仍可以是任意集合。
到目前为止,我正在与之合作:
value
我遇到的问题是,当我在联合中包含interface IFallbackDef {
name: string;
value: object;
}
type ValueDef<TName extends string = string, TOptions extends object = {}> = {
name: TName;
value: TOptions;
};
type Merged<TValueDef extends ValueDef> = (string | TValueDef | IFallbackDef)[];
interface ITest1Options {
foo: string;
bar: string;
}
interface ITest2Options {
baz: string;
qux: string;
}
const test: Merged<
| ValueDef<'test1', ITest1Options>
| ValueDef<'test2', ITest2Options>
> = [
'asdf',
{
name: 'test1',
value: {
foo: 'asdjfkl',
bar: 'asdf',
/**
* Intellisense shows both sets of properties,
* and typescript allows them all, too
*/
qux: 'asdfkljsdg' // This should be an error
}
},
{
name: 'test2',
value: {
baz: 'blah',
qux: 'test',
/**
* Intellisense shows both sets of properties,
* and typescript allows them all, too
*/
foo: 'salfdj' // This should be an error
}
},
{
name: 'asdf',
value: {
/**
* Intellisense shows both sets of properties,
* should show none.
*/
},
},
]
时,各种IFallbackDef
属性的所有类型都会合并。如果我排除value
,则联合可以正常工作,但是IFallbackDef
数组的最后一个索引将是错误的,因为test
是未知的。
我假设因为name: 'asdf'
使用基本类型,并且形状与IFallbackDef
相同,所以它正在合并类型...?此刻,我对如何使其正常工作感到困惑。新鲜的眼睛将不胜感激。
答案 0 :(得分:1)
如果展开“合并”类型,则最终得到的类型如下:
(
| string
| { name: "test1", value: { foo: string, bar: string } }
| { name: "test2", value: { baz: string, qux: string } }
| { name: string, value: object }
)[]
问题在于,这不是受| { name: string, value: object }
歧视的联合。该行中断了区分的联合检查,因为string
与'test1'
和'test2'
都匹配,因此TypeScript不能区分。
您需要删除该行(例如,按照您的建议删除IFallbackDef
),以使受歧视的工会正常工作。不幸的是,我不相信有一种解决方法可以使您实现以下目标:将具有特定键类型的事物归为特定值类型,但是将没有特定键类型之一的事物归为不同值类型
根据您的约束,一种选择是对后备使用不同的密钥。例如:
interface IFallbackDef {
not-name: string;
value: object;
}
这将允许对具有名称键的对象与具有非名称键的对象进行区分的联合类型检查。
答案 1 :(得分:0)