[英]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.