簡體   English   中英

TypeScript類型注釋可表示泛型的可變數量?

[英]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')
    }
}

如何基於SerializerUnionSerializer編寫類型聲明? 顯然,其類型取決於傳遞給它的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] (其中aAbB )傳遞給構造函數,它將推斷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')
  }
}

讓我知道您是否需要我解釋其中的任何內容。 希望能幫助到你。 祝好運!


更新1

@csander

感謝您的回答! 這是我最初的解決方案。 我的問題是,並不是我傳遞的所有類型都一定是具有相同T Serializer<T> 例如,我可能有一個Serializer<string>Serializer<number> ,因此聯合的所需Tstring | 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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM