我有一个相当简单的工厂函数,它使用构造函数的映射来基于传入的字符串参数来确定要创建的对象的正确类型。
我知道在示例中描述的将类构造函数传递给工厂的工厂模式,但是在我的情况下,我需要传递一个简单的字符串。
class Vehicle {
public wheels: number;
}
class Car extends Vehicle {
public drive: number
}
class Bike extends Vehicle {
public ride: number;
}
const CTORS = {
car: Car,
bike: Bike
}
type VehicleTypes = typeof CTORS;
function factory<T extends keyof VehicleTypes>(name: T): InstanceType<VehicleTypes[T]> {
let ctor: VehicleTypes[T] = CTORS[name];
// un-comment to see error
// return new ctor();
return new ctor() as InstanceType<VehicleTypes[T]>;
}
let abc = factory('bike');
abc.ride = 5; // type checks ok
上面的方法和类型检查正常,但是为避免编译器错误,必须在返回值上进行显式键入:
(Type 'Car | Bike' is not assignable to type 'InstanceType<{ car: typeof Car; bike: typeof Bike; }[T]>'. Type 'Car' is not assignable to type 'InstanceType<{ car: typeof Car; bike: typeof Bike; }[T])
我怀疑打字稿在抱怨返回值不是所有潜在实例的并集。但是我不知道如何应用类型,从而不需要显式的键入覆盖。我也尝试了下面的方法,但也无济于事:
type ReturnTypes = {
[P in keyof VehicleTypes]: InstanceType<VehicleTypes[P]>
}
function factory<T extends keyof VehicleTypes>(name: T): ReturnTypes[T] {
let ctor = CTORS[name];
return new ctor();
}
这目前是TypeScript的局限性:无法解析的条件类型,即那些依赖于尚未指定的泛型类型参数的条件类型,对于编译器而言是不透明的;它真的看不到可以为其分配某些值。类型InstanceType<T>
是defined,如下所示:
type InstanceType<T extends new (...args: any) => any> =
T extends new (...args: any) => infer R ? R : any;
这是条件类型,并且inside factory()
的实现,未解析类型InstanceType<VehicleTypes[T]>
,因为未指定T
。
[有几个开放的GitHub问题,并提出了一些建议,以使这些未解决的条件类型更易于处理,但是目前尚未实现(截至TS3.7)。如果您有足够的兴趣去那里给他们a或以其他方式提倡他们,那么这里有一些与他们的链接:
现在,我会说要么像您一样使用类型断言,要么[[或寻找一种不依赖条件类型的方式表示您的类型的方法。此处前进的一种可能方法是,注意TypeScript中的类构造函数被赋予与实例类型相同类型的prototype
属性。这有点奇怪,而且不是真的正确,因为实际的原型将不具有任何仅实例属性,而是that's the way it is and it's unlikely to change。
InstanceType
:type MyInstanceType<T extends { prototype: any }> = T['prototype'];
然后您可以写
function factory<T extends keyof VehicleTypes>(name: T): MyInstanceType<VehicleTypes[T]> { let ctor: VehicleTypes[T] = CTORS[name]; return new ctor(); }
没有错误,您仍然可以进行所需的类型检查:
let abc = factory('bike'); abc.ride = 5; // type checks ok
希望有所帮助;祝你好运!