打字稿-根据提供的对象键检测值类型

时间:2019-06-30 22:18:29

标签: typescript type-inference

鉴于我有一个类似的类型:

type Foo = {
  foo: number;
  bar: string;
  baz: boolean;
}

我想要一种类型Buzz,它可以根据键来检测值类型,即

const abc: Buzz<Foo> = {
  key: 'foo',
  formatter: (detectMe) => {} //I want TS to infer this to be 'number'
};

鉴于键'foo',应该将格式程序中的参数推断为number。我尝试过:

interface ColumnDescription<T> {
  label: string;
  key: keyof T;
  formatter?: (datum: T[keyof T]) => void;
}

但是,这导致参数被推断为number | string | boolean

也尝试过:

interface ColumnDescription<T, K extends keyof T> {
  label: string;
  key: K;
  formatter?: (datum: T[K]) => void;
}

这种工作方式,但我总是需要在第二个类型参数中指定键,而不是自动发生。即:

const abc: Buzz<Foo, 'foo'> = { //I don't want to specify the key
  key: 'foo',
  formatter: (detectMe) => {} //This is inferred correctly
};

1 个答案:

答案 0 :(得分:2)

正如我的评论一样,我建议

type Buzz<T> = {
  [K in keyof T]-?: { key: K; formatter: (d: T[K]) => void }
}[keyof T];

类似于您对Buzz<T, K extends keyof T>所做的操作,但是我没有使用mapped type Buzz来使K需要指定{[K in keyof T]: ...},而是使用了{自动迭代keyof T中的键,并使用相同的键创建一个新对象,但其属性值是您要查找的类型。这意味着要获得所需的Buzz<T>,我们需要look up的属性值,方法是使用[keyof T]对其进行索引。这使Buzz<T>成为类型的并集,其中该并集的每个组成部分对应于您的Buzz<T, K extends keyof T>的特定键K

让我们确保它能起作用:

const abc: Buzz<Foo> = {
  key: "foo",
  formatter: detectMe => {} // inferred as number, as desired
};

看起来不错,让我们使用IntelliSense检查abc的类型:

const abc: {
    key: "foo";
    formatter: (d: number) => void;
} | {
    key: "bar";
    formatter: (d: string) => void;
} | {
    key: "baz";
    formatter: (d: boolean) => void;
}

看起来也不错。

好的,希望能有所帮助;祝你好运!

Link to code