基元的特殊情况泛型类型参数

时间:2016-12-08 17:12:58

标签: generics typescript primitive-types

背景

我在TypeScript中有以下泛型类,它接受构造函数和回调作为其构造函数参数

class InputDataPort<T> {
    constructor(type: new (...args: any[]) => T, listener?: (data: T) => void);
    onUpdate(listener?: (data: T) => void);

    // ... lots of other methods depending on the generic type parameter 'T'
}
var dataPortA = new InputDataPort(Array, array => console.log(array)); // T: Array
var dataPortB = new InputDataPort(Date, array => console.log(array)); // T: Date
...

在这里,我基本上将泛型类型参数定义为构造函数参数。它之所以这样,是因为我需要在运行时知道泛型类型,这种方法可以实现这一点。

问题

但是,我遇到了原始类型的问题。基本上,当我执行以下操作时:

var dataPortN = new InputDataPort(Number, num => console.log(num));

num的类型为Number,TypeScript编译器不允许将Number分配给number(显然,number不能指定为type)的参数:

var myNum: number;

// ERROR: 'number' is a primitive, but 'Number' is a wrapper object ...
var dataPortM = new InputDataPort(Number, num => myNum = num);

在这种情况下(以及其他原始/包装类型的情况),我想使用相应的基元类型作为泛型类型参数T

基本上,我正在寻找以下类型定义:

  • 如果T是数字,则编号
  • 如果T是String,则为else,然后是字符串
  • 如果T是布尔值,则为boolean
  • else T as-is

据我所知,方法重载在这里是不够的,因为它没有提供类级泛型类型。

2 个答案:

答案 0 :(得分:0)

虽然我不确定问题中描述的要求是否可行,但一个可靠的解决方法是为每种基本类型专门化基础InputDataPort类。

例如,要支持number,可以执行以下操作:

class InputNumberDataPort extends InputDataPort<number> {
    constructor(listener?: (data: number) => void) {
        super(Number as any, listener);
    }
}

其余部分与InputStringDataPortInputBooleanDataPort相同,依此类推。此方法将为TypeScript编译器提供正确的泛型类型,并在运行时提供正确的相应构造函数引用。

答案 1 :(得分:0)

Advanced Types > Conditional Types · TypeScript

type PrimitiveMapped2<T> =
  T extends Number ? number :
  T extends String ? string :
  T extends Boolean ? boolean :
  T

class InputDataPort<T> {
  constructor(type: new (...args: any[]) => T, listener?: (data: PrimitiveMapped2<T>) => void) {
    throw new Error('todo')
  }
}

let a = new InputDataPort(Number, num => { // number
  num.toFixed()
})

let b = new InputDataPort(Date, date => { // Date
  date.getTime()
})