在TypeScript中是否有办法编写一个返回泛型类实例的工厂方法,以便自动派生泛型类的特定类型?
在下面的示例中,工厂方法create()
采用枚举值,该值决定实例化返回类的哪个泛型类型参数。但是,属性value
的类型派生为String|Number|Boolean
。是否有可能向编译器明确说明泛型类型与PropertyType
枚举值有关,因此,在这种情况下,value
的类型将是Number
?< / p>
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;
答案 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
中使用PropertyTypeMapping
和looks 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
希望那些帮助。祝你好运!