我定义这种类型的方式有什么问题

type Payload<Es> = {
  trigger:
    Es extends Record<infer K, infer V>
     ? { key: K, data: V } : never
}

type Evs = {
  "item.1": { ok: "Y", code: number }
  "item.2": 1 | 0
}
const payload: Payload<Evs> = {
  trigger: {
    key: "item.1",
    data: 1
  }
}

payload.trigger.data并没有像我预期的那样被推断出来

expected

{ ok: "Y", code: number }

what I get

0 | { ok: "Y", code: number } | 1

推荐答案

Record<K, V> utility type是与属性键为K类型和属性值为V类型的对象相对应的类型.但特定的键与特定的值并不相关. 如果你从{a: string, b: number}开始,然后try 从inferRecord<K, V>,你会得到Record<"a" | "b", string | number>.这与您从{a: number, b: string}中获得的类型相同. 所以你真的不想在这里推断出Record,除非你用want将所有属性混合在一起.

相反,您实际上只需要对类型进行map over次迭代,迭代每个键K,并生成相应的对象类型,然后对映射类型进行index into次即可获得union个属性.也就是说,您想要distributive object type(正如microsoft/TypeScript#47109中创造的那样):

type Payload<E> = {
  trigger: { [K in keyof E]: { key: K, data: E[K] } }[keyof E]
}

您可以验证这是否为您提供了所需的内容:

type Evs = {
  "item.1": { ok: "Y", code: number }
  "item.2": 1 | 0
}

type PEvs = Payload<Evs>;
/* type PEvs = {
    trigger: {
        key: "item.1";
        data: {
            ok: "Y";
            code: number;
        };
    } | {
        key: "item.2";
        data: 0 | 1;
    };
} */

const payload: Payload<Evs> = {
  trigger: {
    key: "item.1",
    data: 1 // error!
  }
}

Playground link to code

Typescript相关问答推荐

了解TS类型参数列表中的分配

如何使类型只能有来自另一个类型的键,但键可以有一个新值,新键应该抛出一个错误

是否可以根据嵌套属性来更改接口中属性的类型?

返回同时具有固定键和变量键的对象的函数的返回类型

在键和值为ARGS的泛型函数中未正确推断类型

迁移到Reaction路由V6时,获取模块Reaction-Router-Dom';没有导出的成员RouteComponentProps错误

通配符路径与每条路径一起显示

如果字符串文字类型是泛型类型,则用反引号将该类型括起来会中断

表单嵌套太深

使用数组作为类型中允许的键的列表

(TypeScript)TypeError:无法读取未定义的属性(正在读取映射)"

自定义 Select 组件的类型问题:使用带逗号的泛型类型<;T与不带逗号的<;T&>;时出错

如何在打字角react 式中补齐表格组

如何扩展RxJS?

如何在Next.js和Tailwind.css中更改悬停时的字体 colored颜色

如何创建一个将嵌套类属性的点表示法生成为字符串文字的类型?

Typescript不允许在数组中使用联合类型

我应该使用服务方法(依赖于可观察的)在组件中进行计算吗?

如何在由函数参数推断的记录类型中具有多个对象字段类型

包含多个不同类构造函数的接口的正确类型?