[英]TypeScript type annotation to express variable numbers of generics?
我一直在将我的项目从JavaScript转换为TypeScript,但是这种类型注释使我感到困惑。 我有一个Serializer
接口和一个用于组合这些接口的类,如下所示:
interface Serializer<T> {
serialize(value: T): ArrayBuffer
}
class UnionSerializer {
constructor(types) {
this.types = types
}
serialize(value) {
for (const type of this.types) {
try {
return type.serialize(value) //throws error if type can't serialize value
}
catch (e) {}
}
throw new Error('No type matched')
}
}
如何基于Serializer
为UnionSerializer
编写类型声明? 显然,其类型取决于传递给它的types
数组。 因此它具有如下接口:
interface UnionSerializerConstructor {
new <T1>([t1]: [Serializer<T1>]): Serializer<T1>
new <T1, T2>([t1, t2]: [Serializer<T1>, Serializer<T2>]): Serializer<T1 | T2>
//...
}
为UnionSerializer
类编写类型注释的最优雅的方法是什么,理想情况下,不写出所有不同types
数组长度的构造函数注释?
new UnionSerializer([a,b])
的类型与new UnionSerializer([b,a])
的类型之间有区别吗? 鉴于您对UnionSerializerConstructor
的类型签名返回了Serializer<A | B>
,因此它看起来并不是真的Serializer<A | B>
Serializer<A | B>
与Serializer<B | A>
相同 Serializer<B | A>
。 在这种情况下,好消息! 您无需担心指定通用的任意长度元组类型,而这是您尚无法做到的 。 而是接受一个数组:
interface UnionSerializerConstructor {
new <T>(types: T[]): Serializer<T>
}
如果将[a,b]
(其中a
是A
, b
是B
)传递给构造函数,它将推断A | B
A | B
代表T
,如您所愿。
现在,您似乎希望传递给构造函数的值本身就是 Serializer
实例。 在这种情况下,您可能应该这样做:
interface UnionSerializerConstructor {
new <T>(types: (Serializer<T>)[]): Serializer<T>
}
我不妨继续为您键入您的UnionSerializer
:
class UnionSerializer<T> implements Serializer<T> {
constructor(public types: (Serializer<T>)[]) {
// next line is unnecessary with "public types" above
// this.types = types
}
serialize(value: T): ArrayBuffer {
for (const type of this.types) {
try {
return type.serialize(value) //throws error if type can't serialize value
}
catch (e) { }
}
throw new Error('No type matched')
}
}
让我知道您是否需要我解释其中的任何内容。 希望能帮助到你。 祝好运!
@csander 说 :
感谢您的回答! 这是我最初的解决方案。 我的问题是,并不是我传递的所有类型都一定是具有相同
T
Serializer<T>
。 例如,我可能有一个Serializer<string>
和Serializer<number>
,因此联合的所需T
为string | number
string | number
但原始Serializer
都没有实现Serializer<string | number>
Serializer<string | number>
。 那有意义吗?
这是一个很好的观点,我未能解决。 简短的回答是,在打字稿泛型类型参数是协变的 ,这意味着,实际上,你总是可以缩小一个Serializer<string|number>
值类型的一个Serializer<string>
:
declare const numberOrStringSerializer: Serializer<number | string>;
const justStringSerializer: Serializer<string> = numberOrStringSerializer;
const justNumberSerializer: Serializer<number> = numberOrStringSerializer;
(这种类型的缩小通常是不合理的,但是出于性能和开发人员方便的原因,TypeScript这样做是可行的 。有可能的修复方法,但它们还不是该语言的一部分。)
话虽如此,但对UnionSerializer
构造函数的类型推断不会自动推断联合类型 :
new UnionSerializer([justNumberSerializer, justStringSerializer]); // error
您可以手动指定它,但是:
new UnionSerializer<string|number>([justNumberSerializer, justStringSerializer]); // ok
这有点烦人,但可以。 可能有一些方法可以改善这种体验,但目前还不确定。 这有帮助吗?
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.