在下面的示例中,我很难弄清楚如何缩小推断的类型。目前,所有格式函数都接受string | number | boolean
并期望返回string | number | boolean
。
理想情况下,我想根据typeID
的值将它们缩小为仅一种类型。
enum TypeID {
Number = "__number__",
String = "__string__",
Boolean = "__boolean__"
}
type Type<TYPE_ID extends TypeID> = {
[TypeID.Number]: number;
[TypeID.String]: string;
[TypeID.Boolean]: boolean;
}[TYPE_ID];
type Item<
TYPE_ID extends TypeID,
TYPE extends Type<TYPE_ID> = Type<TYPE_ID>
> = {
typeID: TypeID;
format: (input: TYPE) => TYPE;
};
type Options<TYPE_ID extends TypeID> = Array<Item<TYPE_ID>>;
const someFunc = <TYPE_ID extends TypeID>(options: Options<TYPE_ID>) => {
return null as any;
};
someFunc([
{
typeID: TypeID.Number,
format: input => input // these should have type "number"
},
{
typeID: TypeID.Boolean,
format: input => input // these should have type "boolean"
},
{
typeID: TypeID.String,
format: input => input // these should have type "string"
}
]);
答案 0 :(得分:1)
使用类似的类型名称(TYPE
vs Type
vs TYPE_ID
vs TypeID
真是令人困惑,因此在以下内容中,我将使它们的名称不同...对于通用参数,我使用一两个大写字母(无论出于何种原因,这都是惯例)。这是Type
:
type Type<T extends TypeID> = {
[TypeID.Number]: number;
[TypeID.String]: string;
[TypeID.Boolean]: boolean;
}[T];
这是Item
:
type Item<T extends TypeID> = {
typeID: T; // <-- T, not TypeID
format: (input: Type<T>) => Type<T>;
};
请注意,您的示例对此做了进一步修改。您在此处有两个类型参数,但似乎仅对第二个使用默认值,因此我将其删除并使用了该默认值。但是这里重要的修改是typeID
属性是泛型类型T
,而不是 concrete 类型TypeID
。我认为您可能打算在您的代码中执行此操作,但是也许很难看到其中的区别。
现在,我要从这里开始的方法是生成一个名为SomeItem
的类型,该类型是所有可能的Item<T>
类型的并集。这种具体类型比通用类型更容易使用:
type _SomeItem<T extends TypeID> = T extends any ? Item<T> : never;
type SomeItem = _SomeItem<TypeID>;
// type SomeItem = Item<TypeID.Number> | Item<TypeID.String> | Item<TypeID.Boolean>
通过在_SomeItem
的定义中使用distributive conditional type,将Item<T>
分布在TypeID
个值的并集上来进行工作。
最后,someFunc
可以是一个具体功能:
const someFunc = (options: Array<SomeItem>) => {
return null as any;
};
使用它时,您会得到预期的推断:
someFunc([
{
typeID: TypeID.Number,
format: input => input // has type number
},
{
typeID: TypeID.Boolean,
format: input => input // has type boolean
},
{
typeID: TypeID.String,
format: input => input // has type string
}
]);
好的,希望能有所帮助。祝你好运!
Link to code