TypeScript:根据另一个字段查找字段的类型

erj*_*ang 5 typescript

假设我有一个这样的界面:

interface Cat {
  weight: number;
  name: string;
  adoptable: boolean;
}
Run Code Online (Sandbox Code Playgroud)

我想定义以下可用于设置值的接口Cat

interface CatUpdate {
  field: keyof Cat;
  value: ???
}
Run Code Online (Sandbox Code Playgroud)

我希望 TypeScript 强制该值是基于字段的适当类型。例如,这应该是无效的:

const x: CatUpdate = {
  field: "name",
  value: 12
}
Run Code Online (Sandbox Code Playgroud)

我如何定义类型CatUpdate.value

jca*_*alz 9

我的倾向是创建CatUpdate一个联合类型而不是接口,如下所示:

interface Cat {
  weight: number;
  name: string;
  adoptable: boolean;
}

type PropUpdate<T extends object> = {
  [K in keyof T]: { field: K; value: T[K] }
}[keyof T];


type CatUpdate = PropUpdate<Cat>;
/* 
type CatUpdate = {
    field: "weight";
    value: number;
} | {
    field: "name";
    value: string;
} | {
    field: "adoptable";
    value: boolean;
}
*/
Run Code Online (Sandbox Code Playgroud)

这对于您提到的用例应该足够有效:

const x: CatUpdate = {
  field: "name",
  value: 12
} // error!
Run Code Online (Sandbox Code Playgroud)

如果需要,您应该能够组合这些 ( CatUpdate | DogUpdate),尽管没有特定的用例,很难知道这种组合是否合适(可以CatDog相互区分吗?也就是说,Cat & Dog不可能?如果Cat & Dog可能,那么CatUpdate | DogUpdate只能用于更新Cat & Dog。如果不可能,那么CatUpdate | DogUpdate可能应该替换为可区分的联合,而不是像(CatUpdate & {kind: "CatUpdate"}) | (DogUpdate & {kind: "DogUpdate"})。)

希望有帮助;祝你好运!

链接到代码


Dan*_*iel 3

一种方法是使用泛型类型:

interface CatUpdate<T extends keyof Cat> {
  field: T;
  value: Cat[T];
}
Run Code Online (Sandbox Code Playgroud)

它可以工作,但这意味着您在创建对象时需要更详细一些。

// Error
const x: CatUpdate<"name"> = {
  field: "name",
  value: 12
}

// No error
const y: CatUpdate<"name"> = {
  field: "name",
  value: "Dave"
}
Run Code Online (Sandbox Code Playgroud)

一种解决方案是使用一个函数进行实例化,该函数可以根据参数推断类型:

function getCatUpdate<T extends keyof Cat>(field: T, value: Cat[T]): CatUpdate<T> {
    return {
        field,
        value
    }
}
Run Code Online (Sandbox Code Playgroud)

你可以这样称呼:

// Error
const x = getCatUpdate("name", 12);

// No error
const y = getCatUpdate("name", "Dave");
Run Code Online (Sandbox Code Playgroud)