在不确切知道您的代码的其余部分将如何使用它的情况下,您正在寻找的类型可以这样表示:
type TResponse<KS extends PropertyKey, KN extends PropertyKey> =
Record<KS, string> & Record<KN, number>;
这是两个Record 类型中的intersection。它说TResponse<KS, KN> 在KS 类型的键处有一个string 属性,在KN 类型的键处有一个number 属性。
你可以这样使用它:
const formData = {
xAxisColumn: 'abc',
periodColumn: 'cde'
} as const;
const response = {
abc: 'some data 1',
cde: 123,
otherColumn: 'bla...'
}
function processResponse<KS extends PropertyKey, KN extends PropertyKey>(
formData: { xAxisColumn: KS, periodColumn: KN },
response: TResponse<KS, KN>
) {
const xAxis: string = response[formData.xAxisColumn];
const period: number = response[formData.periodColumn];
// ... process them here
}
processResponse(formData, response); // okay
processResponse({ xAxisColumn: "x", periodColumn: "p" }, { x: "okay", p: 123 }); // also okay
processResponse({ xAxisColumn: "x", periodColumn: "p" }, { x: 123, p: 456 }); // error!
// number is not assignable to string -------------------> ~
或许
function keyVal<K extends PropertyKey, V>(key: K, val: V) {
return { [key]: val } as Record<K, V>;
}
function makeResponse<KS extends PropertyKey, KN extends PropertyKey>(
formData: { xAxisColumn: KS, periodColumn: KN }
): TResponse<KS, KN> {
return Object.assign(keyVal(formData.xAxisColumn, "x axis data"), keyVal(formData.periodColumn, 123));
}
示例代码的重点是表明,只要编译器知道 literal 的值formData。当KS 和KN 是已知的文字类型时,您会发现TResponse<KS, KN> 更容易使用。
在processResponse()和 makeResponse()的实现中,KS和KN是未指定的泛型类型,编译器对TResponse<KS, KN>的推理变得更加困难,你需要找到迂回的方式来表达操作未指定键的属性,可能涉及type assertions,如上面的keyVal()。
因此,虽然您可以表达TResponse,但这样做可能不值得。
无论如何,希望对您有所帮助;祝你好运!
Playground link to code