繁体   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