打字稿-使用泛型和参数值设置类型

时间:2020-10-06 13:49:17

标签: typescript typescript-generics

我希望有一个具有单个泛型的接口,其中一个属性是keyof T,另一个是在第一个属性上传递的正确的T[keyof T]

以下代码几乎可以满足此要求,正确键入第一个属性(field):

interface RandomType {
    foo: string;
    bar: number;
    baz: boolean;
}

type Typer<T = Record<string, any>> = {
    field: keyof T,
    value: T[any]
}

const param: Typer<RandomType> = {
    field: 'baz',
    value: 'foo'
}

但是,我需要根据value的值输入field

在上一个示例中,它应该触发类型错误,因为RandomType['baz']boolean

2 个答案:

答案 0 :(得分:1)

您希望Typer<T>成为T中每个字段的字段union。您可以通过多种方式执行此操作。例如:

type Typer<T> = { [K in keyof T]: {
    field: K,
    value: T[K]
} }[keyof T];

在这里,我们mapping overT中的属性,以获取其值是所需类型的新对象,然后立即looking up其所有值。

您可以验证Typer<RandomType>是您要查找的内容:

type TyperRandomType = Typer<RandomType>
/* type TyperRandomType = {
    field: "foo";
    value: string;
} | {
    field: "bar";
    value: number;
} | {
    field: "baz";
    value: boolean;
} */

然后您的示例给出了您期望的错误:

const param: Typer<RandomType> = {
    field: 'baz',
    value: 'foo'
}; // error!
// Types of property 'value' are incompatible.
// Type 'string' is not assignable to type 'boolean'

Playground link to code

答案 1 :(得分:0)

这可以做您想要的,但是现在您必须两次指定密钥:

type Typer<T, K extends keyof T> = {
    field: K,
    value: T[K]
}

const param: Typer<RandomType, 'baz'> = {
    field: 'baz',
    value: 'foo' // Type 'string' is not assignable to type 'boolean'. ts(2322)
}

我认为TS存在一个未解决的问题,使得仅指定某些泛型并推断其余泛型成为可能,以便Typer<RandomType>可以正常工作。