typescript - 在方法中推断正确的字符串文字
问题描述
我需要帮助说服 Typescript 推断用户输入的字符串文字,而不是使用具有所有可能值的字符串文字。
看看这个例子(操场链接):
// Supported methods.
type Methods = "GET" | "PUT" /* and etc. */;
// Event interface for each method.
interface Events {
[key: string]: [any, any];
}
// Event objects assigned to methods.
type MethodicalEvents = {
[key in Methods]: Events | undefined;
};
// Extract string keys only.
type EventKeys<E extends Events> = Extract<keyof E, string>;
// Extract all event keys from `MethodicalEvents -> Events`.
type AllEvents<O extends MethodicalEvents, M extends Methods> =
O[M] extends object ? EventKeys<O[M]> : never;
// Extract send value (first array value in `Events` interface).
type ExtractSendValue<O extends MethodicalEvents, M extends Methods, E extends AllEvents<O, M>> =
O[M] extends object ?
O[M][E] extends [any, any] ?
O[M][E][0] :
never :
never;
// Interface implementing stuff from above.
interface Foo extends MethodicalEvents {
PUT: {
"1": [123, void];
"2": [string, void];
"3": [boolean, void];
};
}
// Class for making requests via `Foo` interface.
class Bar<O extends MethodicalEvents> {
public request<M extends Methods, E extends AllEvents<O, M>>(
method: M,
event: E,
data: ExtractSendValue<O, M, E>,
) {
// Do stuff...
}
}
const bar = new Bar<Foo>();
// `true` should not be allowed.
bar.request("PUT", "1", true /*type: `string | boolean | 123`*/);
// type is `123`, as expected
type ExpectedType = ExtractSendValue<Foo, "PUT", "1">;
的第二个参数bar.request
有类型,"1" | "2" | "3"
而我希望它有"1"
一个类型。
我怎样才能做到这一点?
解决方案
我不能肯定地告诉你为什么推理不能像你期望的那样工作,我希望它会这样。AllEvents<O, M>
应该解决 的约束"1"|"2"|"3"
,这反过来应该让编译器推断E
文字类型"1"
。它反而推断"1"|"2"|"3"
.
从我的测试来看,问题在于使用Extract
inExtract<keyof E, string>;
如果我们删除它,推理会按预期工作(尽管您的用例可能需要这样做)。
该错误的解决方法是重新排序AllEvent
. 这似乎有效:
// Supported methods.
type Methods = "GET" | "PUT" /* and etc. */;
// Event interface for each method.
interface Events {
[key: string]: [any, any];
}
// Event objects assigned to methods.
type MethodicalEvents = {
[key in Methods]: Events | undefined;
};
// Extract all event keys from `MethodicalEvents -> Events`.
type AllEvents<O extends MethodicalEvents, M extends Methods> = Extract<O[M] extends object ? keyof O[M] : never, string>
// Extract send value (first array value in `Events` interface).
type ExtractSendValue<O extends MethodicalEvents, M extends Methods, E extends AllEvents<O, M>> =
O[M] extends object ?
O[M][E] extends [any, any] ?
O[M][E][0] :
never :
never;
// Interface implementing stuff from above.
interface Foo extends MethodicalEvents {
PUT: {
"1": [123, void];
"2": [string, void];
"3": [boolean, void];
};
}
// Class for making requests via `Foo` interface.
class Bar<O extends MethodicalEvents> {
public request<M extends Methods, E extends AllEvents<O, M>>(
method: M,
event: E,
data: ExtractSendValue<O, M, E >,
) {
// Do stuff...
}
}
const bar = new Bar<Foo>();
// `true` is not allowed
bar.request("PUT", "1", true /*type: `string | boolean | 123`*/);
// type is `123`, as expected
type ExpectedType = ExtractSendValue<Foo, "PUT", "1">;
推荐阅读
- snowflake-cloud-data-platform - 在教程“教程:使用副本从本地文件系统批量加载”中,my_stage 和 my_table 权限有什么区别?
- maven - 如何定义 maven-release-plugin 执行的子插件的版本?
- javascript - 如何在 javascript 中以这种数组格式返回正确的值?
- python - 创建具有多个子节点的 Python OOP 树(决策树)
- apache-spark - 在 Apache Spark 中持久化 GroupState
- ios - 寻找有关蓝牙 LE“指示”行为的信息
- java - Gradle:使用 spring-boot 构建多项目
- javascript - 从数组中自动完成并获取对应的id
- cmake - 如何删除存储在 add_custom_target 中的 cmake 列表中的文件?
- python - Flask 防止 PUT、DELETE 和 POST