从特定工厂方法参数值派生类的泛型类型

时间:2018-01-11 12:52:25

标签: typescript generics

在TypeScript中是否有办法编写一个返回泛型类实例的工厂方法,以便自动派生泛型类的特定类型?

在下面的示例中,工厂方法create()采用枚举值,该值决定实例化返回类的哪个泛型类型参数。但是,属性value的类型派生为String|Number|Boolean。是否有可能向编译器明确说明泛型类型与PropertyType枚举值有关,因此,在这种情况下,value的类型将是Number?< / p>

&#13;
&#13;
class Property<T> { 
    public value: T;

    public static create(propertyType: PropertyType) {
        if (propertyType === PropertyType.Text) {
            return new Property<string>();
        }
        else if (propertyType === PropertyType.Number) {
            return new Property<number>();
        }
        return new Property<boolean>();
    }
}

enum PropertyType {
    Text,
    Number,
    Boolean,
}

let prop = Property.create( PropertyType.Number );
prop.value = 4;
&#13;
&#13;
&#13;

enter image description here

1 个答案:

答案 0 :(得分:2)

它不推断映射的原因是因为编译器不执行您期望的分析类型。如果检查Property.create()函数的类型,则为:

Property<T>.create(propertyType: PropertyType): Property<string> | 
  Property<number> | Property<boolean>;

它推断函数有时返回Property<string>,有时会返回Property<number>,有时返回Property<boolean>,因此返回类型是所有这些的并集。我很确定它只是看到了不同的return语句,但没有进行控制流案例分析来确定哪些输入值会导致哪些输出值(通常不可能这样做)。

所以你需要明确告诉它有关映射的内容。最简单的方法是在Property.create()上使用function overloads

class Property<T> {
  public value: T;

  public static create(propertyType: PropertyType.Text): Property<string>;
  public static create(propertyType: PropertyType.Number): Property<number>;
  public static create(propertyType: PropertyType.Boolean): Property<boolean>;
  public static create(propertyType: PropertyType) {
    if (propertyType === PropertyType.Text) {
      return new Property<string>();
    }
    else if (propertyType === PropertyType.Number) {
      return new Property<number>();
    }
    return new Property<boolean>();
  }
}

现在,如果您调用该功能,您将看到您的期望:

let prop = Property.create(PropertyType.Number);
prop.value = 4; // inferred as number

还有其他方法可以做到这一点。您可以使用字符串文字而不是枚举,并将映射存储在类型中:

type PropertyTypeMapping = {
  Text: string,
  Number: number,
  Boolean: boolean
}
type PropertyType = keyof PropertyTypeMapping;

然后,您可以将Property.create()表示为一个函数,该函数在PropertyType中使用PropertyTypeMappinglooks up密钥来构建返回类型。您只能查找字符串或数字文字,即使枚举值通常是数字或字符串,它们也不能很好地与查找类型一起使用。这是:

class Property<T> {
  public value: T;

  public static create<K extends PropertyType>(
    propertyType: K
  ): Property<PropertyTypeMapping[K]> {
    if (propertyType === 'Text') {
      return new Property<string>();
    }
    else if (propertyType === 'Number') {
      return new Property<number>();
    }
    return new Property<boolean>();
  }
}

检查它是否有效:

let prop = Property.create('Number');
prop.value = 4; // number

希望那些帮助。祝你好运!