如何使用基于泛型类型的条件类型来描述约束



我的代码中有一个打字问题——生成了联合类型约束,而不是只从ItemProperties类型字典中选择一个类型。在现有ItemType的基础上,有没有办法对ItemConfig内部的props属性进行严格约束?

第页。S.在props类型声明处用元组包装T泛型(如这里所述)并不能解决问题。

简化代码示例:

enum ItemType {
Dog = 1,
Car = 2,
Building = 3,
}
interface ItemProperties {
[Item.Dog]: {
name: string;
};
[Item.Car]: {
power: number;
};
}
interface ItemConfig<T extends ItemType = ItemType> {
type: T;
props: T extends keyof ItemProperties ? ItemProperties[T] : {};
}
const config: ItemConfig[] = [
{
type: ItemType.Dog,
props: ...
}
];

预期typeof props:

{ name: string }

实际typeof props:

{ name: string } | { power: number } | {}

如注释中所述,问题是ItemConfig等于{type: ItemType, props: {} | {name: string} | {power: number}},而您希望它是一个判别并集{type: ItemType.Dog, props: {name: string}} | {type: ItemType.Car, props: {power: number}} | ..,以便正确键入数组元素props

创建这个联合的一种方法是使用分布式条件类型(docs):

type ItemConfig<T = ItemType> = T extends ItemType ? {
type: T;
props: T extends keyof ItemProperties ? ItemProperties[T] : {};
} : never

TypeScript游乐场

因为条件中的T是裸类型参数,所以ItemConfig<ItemType.Dog | ItemType.Car | ItemType.Building>分配给ItemConfig<ItemType.Dog> | ItemConfig<ItemType.Car> | ItemConfig<ItemType.Building>,这是所需的并集。

或者(正如yossarian上尉所说),由于ItemType扩展了PropertyKey(即string | number | symbol),您可以使用映射类型创建一个以所需并集的组成部分为值的对象,并对该对象进行索引以获得并集:

type ItemConfig = {
[T in ItemType]: {
type: T,
props: T extends keyof ItemProperties ? ItemProperties[T] : {}
}
}[ItemType]

TypeScript游乐场

这样做的优点是,您不需要ItemConfig来具有泛型参数T,但它仅限于扩展PropertyKey的类型(否则您不能将其用作映射类型中的键)。

两种方法都产生相同的ItemConfig并集,这将允许为每个数组元素推断出适当的props类型:

const config: ItemConfig[] = [
{
type: ItemType.Dog,
props: {name: 'x'}
// type of props: {name: string}
},
{
type: ItemType.Car,
props: {power: 7}
// type of props: {power: number}
},
{
type: ItemType.Dog,
props: {power: 7} // Type error
// type of props: {name: string}
}
];

最新更新