Arrays 在TypeScript中定义不同泛型类型的数组 接口指令{ 承诺:承诺, 回调?:($html:JQuery,数据:未知)=>void } 常量arr:指令[]=[ {promise:promise.resolve({foo:'bar'}),回调:($html,data)=>console.log(data.foo)}, {promise:promise.resolve({bar:'foo'}),回调:($html,data)=>console.log(data.bar)} ];
鉴于上述情况,我希望TypeScript能够识别回调函数中的数据参数与Promise的解析类型相同 如果它是独立的,我可以做:Arrays 在TypeScript中定义不同泛型类型的数组 接口指令{ 承诺:承诺, 回调?:($html:JQuery,数据:未知)=>void } 常量arr:指令[]=[ {promise:promise.resolve({foo:'bar'}),回调:($html,data)=>console.log(data.foo)}, {promise:promise.resolve({bar:'foo'}),回调:($html,data)=>console.log(data.bar)} ];,arrays,typescript,generics,Arrays,Typescript,Generics,鉴于上述情况,我希望TypeScript能够识别回调函数中的数据参数与Promise的解析类型相同 如果它是独立的,我可以做: interface Instruction { promise: Promise<unknown>, callback?: ($html: JQuery, data: unknown ) => void } const arr: Instruction[] = [ { promise: Promise.resolve({ foo: 'ba
interface Instruction {
promise: Promise<unknown>,
callback?: ($html: JQuery, data: unknown ) => void
}
const arr: Instruction[] = [
{ promise: Promise.resolve({ foo: 'bar' }), callback: ($html, data) => console.log(data.foo) },
{ promise: Promise.resolve({ bar: 'foo' }), callback: ($html, data) => console.log(data.bar) }
];
接口指令{
承诺:承诺,
回调?:($html:JQuery,data:T)=>void
}
但是,我该如何定义数组,其中
T
在每行上的含义可能不同?也许它会帮助您:
type JQuery='JQuery'
接口指令{
承诺:承诺,
回调?:($html:JQuery,data:T)=>void
}
constbuilder=(arg:T):指令=>({promise:promise.resolve(arg),回调:($html,data)=>data})
常数arr=[
生成器({foo:'bar'}),
生成器({bar:'foo'}),
];
如果这个数组是可变的,事情就会变得复杂
更新
您必须添加额外的逗号
,因为没有,
TS认为您试图使用某种react jsx
语法。
你应该只使用箭头功能。它与功能
一样正常工作。
您可以使用
或
而不是额外的逗号,这实际上是的规范用例,在TypeScript中不直接支持(大多数具有泛型的语言也不直接支持它们,因此这不是TypeScript的一个特殊缺点)。有一个开放的特性请求,要求这样做,但它不是TS4.1语言的一部分
TypeScript中的泛型是“通用的”,这意味着当我说class Foo{…}
时,我的意思是它适用于所有可能的类型参数T
。这使得Foo
的消费者可以指定T
的值,并根据自己的意愿使用它,而Foo
的提供者需要考虑所有可能性
您试图描述的异构集合需要“存在”泛型。在某种意义上,您希望接口指令{…}
意味着存在一个类型参数T
。这意味着指令
的提供者可以指定T
的值,并根据需要使用它,而指令
的使用者需要考虑所有可能性
有关通用与存在量化泛型的更多信息,请参阅
虽然TypeScript中没有直接支持存在主义,但有间接支持。普遍意义和存在意义之间的区别与谁在看类型有关。如果你转换生产者和消费者的角色,你就会有类似于生存的行为。这可以通过回调来实现。所以存在主义可以用TypeScript编码
让我们看看如何为指令执行此操作。首先,让我们将指令
定义为一个通用的泛型,即您提到的“独立”版本(我正在删除此代码中的JQuery
依赖项):
SomeInstruction
是一个函数,它调用一个函数,该函数为任何T
接受指令并返回结果。请注意,SomeInstruction
本身如何不再依赖于T
。您可能想知道如何获得SomeInstruction
,但这也是相当简单的。让我们创建一个帮助函数,将任何指令
转换为SomeInstruction
:
interface Instruction<T> {
promise: Promise<T>,
callback?: (data: T) => void
}
type SomeInstruction = <R>(cb: <T>(instruction: Instruction<T>) => R) => R;
根据需要检查所有类型
实际上,使用SomeInstruction
比使用指令要复杂一些,因为它需要回调。但这并不可怕,并且再次允许T
类型参数以消费者不知道实际T
类型的方式出现,因此必须将其视为任何可能的T
:
const arr: SomeInstruction[] = [
someInstruction({
promise: Promise.resolve({ foo: 'bar' }),
callback: (data) => console.log(data.foo)
}),
someInstruction({
promise: Promise.resolve({ bar: 'foo' }),
callback: (data) => console.log(data.bar)
})
]
//在此处写出T以明确
arr.forEach(someInstruction=>someInstruction((i:Instruction)=>{
i、 承诺。那么(i.callback);//起作用了
}))
//但没有必要:
arr.forEach(someInstruction=>someInstruction(i=>{
i、 承诺。那么(i.callback);//起作用了
}))
很好
还有其他解决办法,但存在主义是你真正想要的。为了完整起见,以下是一些可能的变通方法,我将提及但不实施:
- 放弃类型安全,使用
any
或unknown
并使用类型断言返回所需的类型。布莱奇
- 在将类似
[T1,T2,T3]
的类型转换为相应的[Instruction,Instruction,Instruction]
类型时,请使用。但是,这不适用于push()
,因此您也需要设法解决这个问题
- 重构
指令
,以便不需要/公开泛型。无论消费者打算用指令做什么,它都必须独立于T
(例如,我可以编写I.promise.then(I.callback)
,但我不能做太多其他事情,对吗?),所以制作一个指令
泛型函数,它需要一个有效的promise和callback对来创建,并返回一些非泛型的东西,包括您需要的任何功能,仅此而已。从某种意义上说,这是一个“精简”的存在主义,不允许使用者单独访问内部承诺回调对
在您的实际代码中,arr
是否是一个长度和类型在编译时已知的不可变数组
const someInstruction = <T,>(i: Instruction<T>): SomeInstruction => cb => cb(i);
const arr: SomeInstruction[] = [
someInstruction({
promise: Promise.resolve({ foo: 'bar' }),
callback: (data) => console.log(data.foo)
}),
someInstruction({
promise: Promise.resolve({ bar: 'foo' }),
callback: (data) => console.log(data.bar)
})
]
// writing out T for explicitness here
arr.forEach(someInstruction => someInstruction(<T,>(i: Instruction<T>) => {
i.promise.then(i.callback); // works
}))
// but it is not necessary:
arr.forEach(someInstruction => someInstruction(i => {
i.promise.then(i.callback); // works
}))