英文:
Type Polymorphic Functions using Enums
问题
我有一个具有以下签名的工厂方法:
enum FactoryType {
CAR = 'CAR',
BIKE = 'BIKE'
}
type CarParamType = {
cylinders: number
}
type BikeParamType = {
gears: number
}
factory<F extends FactoryType>(factoryType: F, params: ParamType<F>) {
switch (factoryType) {
case FactoryType.CAR:
return new CarFactory(params);
case FactoryType.BIKE:
return new BikeFactory(params);
default:
throw new Error('unrecognized factory');
}
}
BikeFactory
和 CarFactory
将具有接受各自参数类型的构造函数。在 TypeScript 中,有没有一种方法可以根据枚举来确定 ParamType
的实际类型,以便在工厂方法中尝试将参数传递给它们的构造函数时不会出现编译错误?
我认为 ParamType
可能如下所示:
type ParamType<T> = T extends FactoryType.CAR ? CarParamType
: T extends FactoryType.BIKE ? BikeParamType : never;
但我认为这里缺少足够的“提示”来为编译器提供所需的信息。
英文:
I have a factory method with the following signature:
enum FactoryType {
CAR = 'CAR',
BIKE = 'BIKE'
}
type CarParamType = {
cylinders: number
}
type BikeParamType = {
gears: number
}
factory<F extends FactoryType>(factoryType: F, params: ParamType<F>) {
switch (factoryType) {
case FactoryType.CAR:
return new CarFactory(params);
case FactoryType.BIKE:
return new BikeFactory(params);
default:
throw new Error('unrecognized factory');
}
}
Where BikeFactory
and CarFactory
would have constructors that took in their respective param types.
Is there a way for me to do this in Typescript? That is, using an Enum, determine the actual type of the ParamType
is such that I don't get compile errors within the factory method when I try to pass the params
into their respective constructors?
I thought ParamType
could look something like this:
type ParamType<T> = T extends FactoryType.CAR ? CarParamType
: T extends FactoryType.BIKE ? BikeParamType : never;
But I don't think there's enough "hints" to give the compiler what it needs.
答案1
得分: 1
以下是您要的翻译部分:
The only supported way to get the narrowing to work with switch
/case
statements if for factoryType
and params
to be part of a discriminated union where factoryType
is the discriminant property. That requires that they be packaged in a single object, and even though it doesn't look like it, they are. You can think of factory()
as having a rest parameter whose type is a discriminated union of tuple types:
唯一支持的使 switch
/case
语句与 factoryType
和 params
协同工作的方法是它们必须成为 判别联合 的一部分,其中 factoryType
是 判别属性。这要求它们被打包在一个单一对象中,尽管看起来并不像,但实际上它们是。您可以将 factory()
视为具有判别联合 元组类型 的 剩余参数:
function factory(
...args:
[FactoryType.CAR, CarParamType] |
[FactoryType.BIKE, BikeParamType]
) {
switch (args[0]) {
case FactoryType.CAR:
return new CarFactory(args[1]); // okay
case FactoryType.BIKE:
return new BikeFactory(args[1]); // okay
}
}
That works, but you've lost your factoryType
and params
names. Luckily, TypeScript also supports destructured discriminated unions, where you destructure into separate variables but the compiler keeps track of the relationship between those variables as if they were properties of the original discriminated union. That brings us to:
这样可以正常工作,但您失去了 factoryType
和 params
的名称。幸运的是,TypeScript 还支持解构的 判别联合,在这里,您将其解构为单独的变量,但编译器会跟踪这些变量之间的关系,就好像它们是原始判别联合的属性。这将我们带到:
function factory(
...[factoryType, params]:
[FactoryType.CAR, CarParamType] |
[FactoryType.BIKE, BikeParamType]
) {
switch (factoryType) {
case FactoryType.CAR:
return new CarFactory(params); // okay
case FactoryType.BIKE:
return new BikeFactory(params); // okay
}
}
The code compiles to the slightly weird function factory(...[factoryType, params]) {...}
instead of function factory(factoryType, params) {...}
, but it acts the same.
这段代码编译成了稍微奇怪的 function factory(...[factoryType, params]) {...}
,而不是 function factory(factoryType, params) {...}
,但它的行为是相同的。
英文:
The only supported way to get the narrowing to work with switch
/case
statements if for factoryType
and params
to be part of a discriminated union where factoryType
is the discriminant property. That requires that they be packaged in a single object, and even though it doesn't look like it, they are. You can think of factory()
as having a rest parameter whose type is a discriminated union of tuple types:
function factory(
...args:
[FactoryType.CAR, CarParamType] |
[FactoryType.BIKE, BikeParamType]
) {
switch (args[0]) {
case FactoryType.CAR:
return new CarFactory(args[1]); // okay
case FactoryType.BIKE:
return new BikeFactory(args[1]); // okay
}
}
That works, but you've lost your factoryType
and params
names. Luckily, TypeScript also supports destructured discriminated unions, where you destructure into separate variables but the compiler keeps track of the relationship between those variables as if they were properties of the original discriminated union. That brings us to:
function factory(
...[factoryType, params]:
[FactoryType.CAR, CarParamType] |
[FactoryType.BIKE, BikeParamType]
) {
switch (factoryType) {
case FactoryType.CAR:
return new CarFactory(params); // okay
case FactoryType.BIKE:
return new BikeFactory(params); // okay
}
}
The code compiles to the slightly weird function factory(...[factoryType, params]) {...}
instead of function factory(factoryType, params) {...}
, but it acts the same.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论