typescript - 从索引联合类型推断原始类型
问题描述
有没有办法从作为索引类型创建的类型联合中推断出原始类型?这是一个例子。
class FooHandler { type: "Foo" = "Foo"; }
class GooHandler { type: "Goo" = "Goo"; }
class UniHandler { type: "A" | "B" | "C" = "A"; }
type HandlerVariant = FooHandler | GooHandler | UniHandler;
type HandlerTypeVariant = HandlerVariant["type"];
// Infer the concrete `HadnlerVariant`
type HandlerFromType<Type extends HandlerTypeVariant> = ??;
最终,我希望能够创建一个映射类型,每个映射类型都type
包含该类型处理程序的一个实例。
type HandlerRegistryType = {
[Type in HandlerTypeVariant]: HandlerFromType<Type>;
}
编辑:
在这种更复杂的情况下,似乎公认的解决方案在派生类型方面存在一些问题。-链接到 ts 游乐场-。
除了type
上面的代码片段之外,我还添加了一个Id
and CodeTemplate
,其中两者都由HandlerFromType<Type>
. 添加Id
一切正常后,但是当我添加 时CodeTemplate
,突然类型检查失败,好像HandlerFromType<Type>
推断为所有处理程序一样。
编辑2:
我似乎找到了问题的根源。这是ts playground上最小示例的链接。由于它的模板HandlerFromType
有一个默认值,当它在里面使用时,使用这个默认值。然后在声明中,错误不可分配给.U
CodeTemplate
codeTemplate
FooHandler
GooHandler
解决方案
您可以使用该Extract
类型来获取扩展特定类型的联合成员。这将按您的预期工作:
class FooHandler { type: "Foo" = "Foo"; }
class GooHandler { type: "Goo" = "Goo"; }
type HandlerVariant = FooHandler | GooHandler;
type HandlerTypeVariant = HandlerVariant["type"];
type HandlerFromType<Type extends HandlerTypeVariant> = Extract<HandlerVariant, { type: Type }>;
type HandlerRegistryType = {
[Type in HandlerTypeVariant]: HandlerFromType<Type>;
}
编辑
如果type
是其中一个成员中的联合,则可以构造一个运行良好的版本,但它有点复杂并且需要分布式条件类型:
class FooHandler { type: "Foo" = "Foo"; foo: string }
class GooHandler { type: "Goo" = "Goo"; goo: string}
class UniHandler { type: "A" | "B" | "C" = "A"; uni: string}
type HandlerVariant = FooHandler | GooHandler | UniHandler;
type HandlerTypeVariant = HandlerVariant["type"];
type HandlerFromType<T, U extends { type: HandlerTypeVariant } = HandlerVariant> =
U extends U ? // Distribute over U, from here on U will be each meber of the union in turn
T extends U["type"] ? U : never // if the single elemnt T extends whatever union U has at type then we take U otherwise we remove it
: never;
type HandlerRegistryType = {
[Type in HandlerTypeVariant]: HandlerFromType<Type>;
}
// same as { Foo: FooHandler; Goo: GooHandler; A: UniHandler; B: UniHandler; C: UniHandler; }
推荐阅读
- node.js - 有没有办法阻止从网络上的其他设备访问 localhost:3000 ?
- surveyjs - SurveyJS 异步 onValueChanging 处理程序
- c# - RedirectToAction 没有将用户发送到正确的页面
- swift - SwiftUI:使用“if else”更改视图
- javascript - 如何修复“未定义不是对象(评估'form.submit.addEventListener')”
- rx-java2 - 在 RxAndroidBle 中,如何返回 ObservableSource
!>!来自 Observable.combineLatest() 而不是 Unit? - python - 第一次使用 Flask 创建网站时,我不断出现“错误:创建数据库时没有这样的命令 'init-db'”
- api - 如何使用 Offest 使用 Airtable API 获得超过 100 行?
- python - 将字体大小转换为轴单位
- html - 阻止 X-Frame Firefox => 如何在 Html5 上启用?