我有一个情况,我有一个泛型项数组(Item
),在项本身中,我希望泛型参数是推断的和特定的。
也就是说,我想有一个泛型项的数组,但是每个泛型项可以有不同的泛型类型,并且应该保留。
type Item<T> = {
value: T;
fn: (value: T) => void;
}
function usesItem<T>(item: Item<T>) {
}
// This is fine - the value is inferred
usesItem({
value: 999,
fn: (value) => {
//value is inferred as number
}
})
第一种方法,声明一个Array<Item<unknown>
:
function usesItems1(items: Array<Item<unknown>>) {
}
usesItems1([{
value: 999,
fn: (value) => {
// value is unknown - we want it to be number
}
}
])
第二种方法:从函数中引入泛型:
function usesItems2<T>(items: Array<Item<T>>) {
}
// appears to work...
usesItems2([{
value: 999,
fn: (value) => {
// value is number
}
}
])
// ...but it doesn't really
usesItems2([{
value: 999,
fn: (value) => {
// value is number
}
}, {
// Type 'string' is not assignable to type 'number'.(2322)
value: "aaa",
fn: (value) => {
}
}
]);
第三种方法-使用infer
关键字,我尝试了几种方法:
type InferredItem1<T> = T extends Item<infer R> ? Item<R> : never;
function usesItems3(items: Array<InferredItem1<unknown>>) {
}
usesItems3([{
//Type 'number' is not assignable to type 'never'.(2322)
value: 999,
fn: (value) => {
}
}
]);
type InferredItem2<T extends Item<unknown>> = T extends Item<infer R> ? Item<R> : never;
function usesItems3b(items: Array<InferredItem2<Item<unknown>>>) {
}
usesItems3b([{
value: 999,
fn: (value) => {
// value is unknown
}
}
]);
TypeScript Playground
我怎样才能实现我想要的?
或者,如果这是不可能的,我想一个规范的参考Github的问题/类似的进入它。
3条答案
按热度按时间wko9yo5t1#
好吧,我有一些工作,但它的怪异和黑客,我不知道如果我是正确的 * 为什么 * 它的作品。第一部分是直截了当的:
createRoutes
函数需要是泛型的,以便有一个类型参数可以推断:奇怪的是
requestBodyValidator
需要写成方法而不是箭头函数,但是createHandler
需要保持箭头函数:Playground链接
我最好的猜测是,通过使
requestBodyValidator
成为一个方法,在推断整个对象的类型时会考虑它的类型,因为Typescript在这个意义上将方法视为“对象的一部分”。Typescript将其视为子表达式,并且其类型是从上下文推断的。的类型被推断,那么它的类型就不能被用来推断对象的类型。也许是别的原因rbl8hiat2#
<T>function(i: T) {...}
,它必须适用于所有可能的类型T
。<T>function(i: T) {...}
,函数定义决定了它适用的一组类型,当你调用函数时,你需要考虑所有可能的类型。是的,这有点难以理解。*以上斜体文字是jcalz这篇文章的释义。
你可以在TypeScript中用回调实现存在泛型。这是你的代码,重写后允许你的异构数组。
这是您的
Item
类型:现在我们为
Item
创建一个存在泛型版本:不,
ExistentialItem
是接受回调并返回回调结果的函数类型。回调接受T
类型的Item
并返回结果。注意,ExistentialItem
的类型不再依赖于Item
的类型。您需要将所有Item
转换为ExistentialItem
,因此为此编写一个helper。现在,您可以使用
ExistentialItem
将异构阵列键入为:这个数组的所有类型检查都通过了。需要注意的是,至少在我看来,使用这个
ExistentialItem
数组要做更多的工作。假设你希望你的
useItems
返回一个数组,其中包含数组中所有对象的键。而不是像你通常写的那样,如果它是一个同构数组:你必须先调用
ExistentialItem
。这里我们传递回调,在回调中我们决定如何处理项,而不是直接使用项。
这取决于你决定是否需要对异构数组进行类型检查。如果你知道数组的大小,你可以使用
[Item<number>, Item<string>]
,这是一个不错的解决方案,但是然后推到数组或试图访问大于2的索引会导致问题。或者你可以使用any
,并使用类型Assert再次进行类型检查。这不是一个好的解决方案。因此,让我们只希望存在类型在某个时候被实现到TS中。
为了完整起见,我们再看一遍整个代码:
同时检查this answer和this answer,以更好地解释通用类型和存在类型。
w51jfk4q3#
让我知道它是否适合你:
Playground
**P.S.我无耻地窃取了@卡亚关于使用方法而不是箭头函数的想法。
我不能用箭使它工作