鉴于我有一个类似的类型:
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
};
答案 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;
}
看起来也不错。
好的,希望能有所帮助;祝你好运!