typescript - 将一组参数化泛型类型转换为一个泛型类型,该泛型类型通过与原始泛型集分离的参数进行参数化
问题描述
如何covert
从下面的示例中定义函数?
const result: BoxType<{
name: "foo",
value: FooType
} | {
name: "bar",
value: BarType
}> = /* --> */ convert<{
foo: FooType,
bar: BarType
}>({
foo: BoxType<FooType>(),
bar: BoxType<BarType>()
}) /* <-- */
我可以想出这样的东西
type Input<T> = {[type in keyof T]: BoxType<T[type]>}
type Output<T> = BoxType<{type: keyof T, value: T[keyof T]}>
function convert<T>(input: Input<T>): Output<T> {
/* ... */
}
但Output
类型显然无效。这甚至可行吗?:)
解决方案
假设我们有一些这样的定义:
interface BoxType<T> { box: T }
interface FooType { foo: string }
interface BarType { bar: string }
declare function BoxType<T>(): BoxType<T>;
我们可以给convert()
函数以下调用签名:
declare function convert<T extends object>(
input: { [K in keyof T]: BoxType<T[K]> }
): BoxType<{ [K in keyof T]-?: { name: K, value: T[K] } }[keyof T]>;
我认为这符合你想要的方式:
const result = convert({
foo: BoxType<FooType>(),
bar: BoxType<BarType>()
})
/*
const result: BoxType<{
name: "foo";
value: FooType;
} | {
name: "bar";
value: BarType;
}>
*/
该convert()
函数是通用的T
,一个对象类型从不直接用作输入或输出,但看起来像input
具有“未装箱”属性的类型。我们可以将input
类型定义T
为直接映射类型。{[K in keyof T]: BoxType<T[K]> }
,我们将每个属性“装箱”。由于input
映射的类型超过keyof T
,这被认为是“同态”映射类型,编译器可以从推断 。到目前为止,这与您所拥有的相同。T
input
对于函数的返回类型,我们希望获取每个属性键并生成 的并K
集。在您的代码中,您在映射之前先使用联合。但是该类型允许来自一个键和另一个键的各种不良值。为了使它们分开,我们需要遍历 中的每个键,一个简单的方法是使用另一种映射类型,例如.keyof T
{ name: K, value: T[K] }
{name: keyof T, value: T[keyof T]}
name
value
K
keyof T
{[K in keyof T]: {name: K, value: T[K]}}
当然,这种类型看起来像{foo: {name: "foo", value: FooType}, bar: {name: "bar", value: BarType}}
......属性值类型是我们想要获得并集的类型,我们根本不需要键。幸运的是,在这里我们可以对它进行索引keyof T
以产生属性值类型的联合。因此 。{[K in keyof T]: {name: K, value: T[K]}}[keyof T]
最后我们将其包装在BoxType
:中。全部做完!等等,哎呀,它与上述输出类型之间的唯一区别是我们通过确保它们不是可选的来修改映射类型的属性:如果您的输入类型恰好具有可选属性, 这可以防止讨厌的值潜入。现在我们完成了。BoxType<{ [K in keyof T]: { name: K, value: T[K] }}[keyof T]>
BoxType<{ [K in keyof T]-?: { name: K, value: T[K] } }[keyof T]>
undefined
T
推荐阅读
- php - 在 sql 中使用 COUNT 时。我收到错误未定义的索引
- visual-studio - 由于缺少 MVC 4,EPiServer 7.5 CMS 无法安装,但我已经安装了 Visual Studio 2017
- ruby-on-rails - Rails 活动存储无法自动加载常量 ActiveStorage::Blob::Analyzable
- angular - 如何在 URL Angular 2 中动态添加路由路径
- git - 当我从有新文件的本地分支执行 git fetch 和 git checkout origin/branch 时,实际上会发生什么?
- ruby-on-rails - Ajax :remote => true 不工作
- java - JDK 10 模块和 sun.security.provider.certpath.SunCertPathBuilderException
- c# - 将 JSON 字符串中的 DateTime 从客户端时间解析为服务器时间
- mysql - 如何编辑 mysql 表以自动启用 created_at 和 updated_at 字段?
- dart - 如果嵌套在子级中,则不会呈现 StreamBuilder 小部件:
[]