Typescript:是否可以确保键和内部值是相同的字符串?

标签 typescript typescript-generics type-constraints

我有一个可能会变大的数据记录。我想知道是否可以强制记录的键与内部名称值相同?

interface Person<T> {
  name: T
  title: string
  description: string
}

type People = Record<string, Person<string>>

// example data

const data: People = {
  sarah: {
    name: 'sarah',
    title: 'Sarah',
    description: 'Hello',
  }
}

const badData: People = {
  adam: {
    name: 'john', // This would cause a typescript error ideally.
    ...
  }
}

我尝试使用通用设置 People,但它需要我将所有键添加到我宁愿避免的联合类型中。 keyof 不起作用,因为在需要 keyof 的地方 undefined object 。

type People<T> = Record<T, Person<T>>

const people: People<keyof typeof people> = {} // Block-scoped variable 'people' used before its declaration.ts(2448)

最佳答案

为了做到这一点,您需要使用额外的函数。

interface Person<T> {
    name: T
    title: string
    description: string
}

type People = Record<string, Person<string>>


type Validate<T extends People> = {
    [Name in keyof T]: Name extends T[Name]['name'] ? T[Name] : T[Name] & { name: never }
}


const validator = <
    Name extends string,
    Human extends Person<Name>,
    Data extends Record<Name, Human>
>(data: Validate<Data>) => data

const result = validator({
    sarah: {
        name: 'sarah',
        title: 'Sarah',
        description: 'Hello',
    },
    adam: {
        name: 'john', // Error.
        title: 'Sarah',
        description: 'Hello',
    }
})

Playground

Validate 迭代每个对象 key/Name 并检查顶级名称是否相等对象[名称]['名称']。如果是 - 返回相同的嵌套对象。如果没有 - 返回相同的嵌套对象,但具有 iverriden name proeprty never

因此,您在应该修复的地方遇到了错误。

如果您对函数参数的类型推断感兴趣,您可以查看我的 article

来自@Konrad Madej验证的更通用版本:

type Validate<Data extends People> = {
    [Name in keyof Data]: Name extends Data[Name]['name'] ? Data[Name] : Omit<Data[Name], 'name'> & { name: Name }
}

如果您有数字键,请考虑以下示例:

interface PayloadObj<T> {
    elementId: T;
    values: any;
}

type Payload = Record<number, PayloadObj<number>>;

type Validate<T extends Payload> = {
    [Key in keyof T]: T[Key] & { elementId: Key }
};

const validator = <
    ElementId extends number,
    PayloadValue extends PayloadObj<ElementId>,
    Data extends Record<ElementId, PayloadValue>
>(data: Validate<Data> & Data): Payload => data;

const result = validator({
    0: {
        elementId: 0,
        values: 'Hello',
    },
    1: {
        elementId: 2, // Error.
        values: 'World',
    },
});

Playground

关于Typescript:是否可以确保键和内部值是相同的字符串?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/69417437/

相关文章:

typescript - 从 Typescript 中的联合类型推断回调参数类型的最佳方法是什么?

typescript - 是否可以为多类型参数类/函数的多个参数创建类型别名?

c# - 如何将 T 限制为无符号积分?

c# - 具有新类型约束的通用构造函数

typescript - 从第一个参数自动推断出第二个通用参数

javascript - 根据从表单中选择的值在屏幕上显示数据

angular - JhiEventManager 多个订阅

typescript - 从同级属性推断/缩小函数参数

haskell - 不同种类的类型类约束

node.js - 如何使用 nestjs 和 socket.io 创建房间