我有以下目的:

const schema = {
  student: {id: 'student/student'},
  students: {id: 'student/students'},
} as const;

interface Schema {
    readonly [key: string]: {id: string};
}

type Mapped<V extends Schema, U extends keyof V> = {
    [S in V[U]['id']]: V[U];
}

但是当我使用这种类型时,所有的值都可以在每个键上使用

const a: Mapped<typeof schema, keyof typeof schema> = {
    'student/student': {id: 'student/student'},
    'student/students': {id: 'student/student'},
}

推荐答案

原因

type Mapped<V extends Schema, U extends keyof V> = {
    [S in V[U]['id']]: V[U];
}

不起作用是因为union type-V[U]独立于S.您需要提取与S对应的V[U]的成员才能正常工作:

type Mapped<V extends Schema, U extends keyof V> = {
  [S in V[U]['id']]: Extract<V[U], { id: S }>;
}

type M = Mapped<typeof schema, keyof typeof schema>;
/* type M = {
    "student/student": {
        readonly id: "student/student";
    };
    "student/students": {
        readonly id: "student/students";
    };
} */

在这里,我使用Extract utility typeV[U]筛选为仅匹配{id: S}的成员.


一个更简单的方法是直接覆盖V[U]的union成员,然后remap这些成员的id属性的键:

type Mapped<V extends Schema, U extends keyof V> = {
  [W in V[U] as W["id"]]: W;
}

type M = Mapped<typeof schema, keyof typeof schema>;
/* type M = {
    "student/student": {
        readonly id: "student/student";
    };
    "student/students": {
        readonly id: "student/students";
    };
} */

因此,您不必丢弃id属性以外的所有属性S,然后在V[U]中重新搜索以找到合适的unions 成员,而是始终持有合适的unions 成员W.

Playground link to code

Typescript相关问答推荐

如何使用另一个类型的属性中的类型

如何根据参数的值缩小函数内的签名范围?

如何在不使用变量的情况下静态判断运算式的类型?

如何从具有给定键列表的对象类型的联合中构造类型

带有微前端的动态React路由问题

如果一个变量不是never类型,我如何创建编译器错误?

具有动态键的泛型类型

如何编写一个类型脚本函数,将一个对象映射(转换)为另一个对象并推断返回类型?

如何编写在返回函数上分配了属性的类型安全泛型闭包

FatalError:Error TS6046:';--模块分辨率';选项的参数必须是:'; node ';,'; node 16';,'; node

使用条件类型的类型保护

如何按属性或数字数组汇总对象数组

在打字脚本中对可迭代对象进行可变压缩

如何将spread operator与typescripts实用程序类型`参数`一起使用

基于未定义属性的条件属性

如何从抽象类的静态方法创建子类的实例?

如何实现允许扩展泛型函数参数的类型

在Typescript 中,是否有一种方法来定义一个类型,其中该类型是字符串子集的所有可能组合?

Typescript 编译错误:TS2339:类型string上不存在属性props

为什么我们在条件语句中使用方括号[]?