TypeScript 中的命令和响应泛型
Command and response generics in TypeScript
我正在努力为 Command -> Response 泛型想出一个好的结构。
我的目标是让函数根据类型或接口接受命令列表中的命令,并使用该接口推断响应类型。
到目前为止,我已经设法根据 type
属性 正确推断出预期的 data
,但我似乎无法全神贯注地推断出 return 通用类型。
非常欢迎任何指向类似示例的指针!我没能找到多少
代码示例:
TypeScript Playground
type MappedData<E, T extends keyof E> = E[T];
type MappedType<E> = {
[K in keyof E]: {
type: K;
data: MappedData<E, K>;
};
}[keyof E];
interface ServerCommandInterface<T> {
_res?: T;
}
interface TestCommandA extends ServerCommandInterface<{responseA: boolean}> {
param_a: string;
}
interface TestCommandB extends ServerCommandInterface<{responseB: boolean}> {
param_b: string;
}
interface Commands {
command_a: TestCommandA;
command_b: TestCommandB;
}
function execute<C extends MappedType<Commands>>(command: C): typeof command.data._res {
// Logic (HTTP call or similar) that would result in _res type
return null as any;
}
const result = execute({
type: 'command_a',
data: {
param_a: 'param',
}
});
console.log(result.responseA); // I expect this to be a boolean
所以我认为您正在寻找的是类似于以下助手类型的东西:
interface Commands {
command_a: {
param: { param_a: string },
response: { responseA: boolean }
},
command_b: {
param: { param_b: string },
response: { responseB: boolean }
}
}
这里 Commands
的每个 属性 都有一个键对应于传递给 execute()
的值的 type
属性。该值是具有两个属性的对象类型:param
和 response
。 param
属性对应传给execute()
的值的data
属性,而response
属性对应值 return 来自 execute()
。请注意,名称 param
和 response
是完全任意的,我们可以随意命名。这里不会涉及 Commands
类型的任何值;它只是一个辅助类型,允许我们以一种简单的方式表达 execute()
的调用签名:
function execute<K extends keyof Commands>(
command: { type: K, data: Commands[K]['param'] }
): Commands[K]['response'] {
return null as any;
}
所以execute()
函数是generic in the type parameter K
, constrained to be one of the keys of Commands
. Then the parameter to execute()
has a type
property of type K
, and a data
property of type Commands[K]['param']
. (We're using indexed access types获取Commands
的K
键控属性的类型,然后得到"param"
-keyed 属性)。 return 类型是 Commands[K]['response']
.
让我们看看它是否有效:
const result = execute({
type: 'command_a',
data: {
param_a: 'param',
}
});
此处编译器推断 "command_a"
为 K
,因此调用签名指定为
/* function execute<"command_a">(command: {
type: "command_a";
data: {
param_a: string;
};
}): {
responseA: boolean;
} */
因此 result
是类型
/* const result: {
responseA: boolean;
} */
符合预期:
result.responseA === true // okay
我正在努力为 Command -> Response 泛型想出一个好的结构。
我的目标是让函数根据类型或接口接受命令列表中的命令,并使用该接口推断响应类型。
到目前为止,我已经设法根据 type
属性 正确推断出预期的 data
,但我似乎无法全神贯注地推断出 return 通用类型。
非常欢迎任何指向类似示例的指针!我没能找到多少
代码示例: TypeScript Playground
type MappedData<E, T extends keyof E> = E[T];
type MappedType<E> = {
[K in keyof E]: {
type: K;
data: MappedData<E, K>;
};
}[keyof E];
interface ServerCommandInterface<T> {
_res?: T;
}
interface TestCommandA extends ServerCommandInterface<{responseA: boolean}> {
param_a: string;
}
interface TestCommandB extends ServerCommandInterface<{responseB: boolean}> {
param_b: string;
}
interface Commands {
command_a: TestCommandA;
command_b: TestCommandB;
}
function execute<C extends MappedType<Commands>>(command: C): typeof command.data._res {
// Logic (HTTP call or similar) that would result in _res type
return null as any;
}
const result = execute({
type: 'command_a',
data: {
param_a: 'param',
}
});
console.log(result.responseA); // I expect this to be a boolean
所以我认为您正在寻找的是类似于以下助手类型的东西:
interface Commands {
command_a: {
param: { param_a: string },
response: { responseA: boolean }
},
command_b: {
param: { param_b: string },
response: { responseB: boolean }
}
}
这里 Commands
的每个 属性 都有一个键对应于传递给 execute()
的值的 type
属性。该值是具有两个属性的对象类型:param
和 response
。 param
属性对应传给execute()
的值的data
属性,而response
属性对应值 return 来自 execute()
。请注意,名称 param
和 response
是完全任意的,我们可以随意命名。这里不会涉及 Commands
类型的任何值;它只是一个辅助类型,允许我们以一种简单的方式表达 execute()
的调用签名:
function execute<K extends keyof Commands>(
command: { type: K, data: Commands[K]['param'] }
): Commands[K]['response'] {
return null as any;
}
所以execute()
函数是generic in the type parameter K
, constrained to be one of the keys of Commands
. Then the parameter to execute()
has a type
property of type K
, and a data
property of type Commands[K]['param']
. (We're using indexed access types获取Commands
的K
键控属性的类型,然后得到"param"
-keyed 属性)。 return 类型是 Commands[K]['response']
.
让我们看看它是否有效:
const result = execute({
type: 'command_a',
data: {
param_a: 'param',
}
});
此处编译器推断 "command_a"
为 K
,因此调用签名指定为
/* function execute<"command_a">(command: {
type: "command_a";
data: {
param_a: string;
};
}): {
responseA: boolean;
} */
因此 result
是类型
/* const result: {
responseA: boolean;
} */
符合预期:
result.responseA === true // okay