我认为正确的方法是创建一个不可变的键名数组并给它一个窄类型,以便编译器将其识别为包含字符串文字类型 https://www.typescriptlang.org/docs/handbook/advanced-types.html#string-literal-types而不是仅仅string
。这是最简单的const断言 https://www.typescriptlang.org/docs/handbook/release-notes/typescript-3-4.html#const-assertions:
const humanProps = ["weight", "height", "age"] as const;
// const humanProps: readonly ["weight", "height", "age"]
然后你可以定义HumanProp
就其而言:
type HumanProp = typeof humanProps[number];
其余代码应该或多或少按原样工作,除了当您迭代键时,您应该使用上面的不可变数组而不是Object.keys()
:
type Human = Record<HumanProp, number>;
const alice: Human = {
age: 31,
height: 176,
weight: 47
};
const humanPropLabels: Readonly<Record<HumanProp, string>> = {
weight: "Weight (kg)",
height: "Height (cm)",
age: "Age (full years)"
};
function describe(human: Human): string {
let lines: string[] = [];
for (const key of humanProps) { // <-- iterate this way
lines.push(`${humanPropLabels[key]}: ${human[key]}`);
}
return lines.join("\n");
}
不使用的原因Object.keys()
是编译器无法验证类型的对象Human
will only已在中声明密钥Human
。 TypeScript 中的对象类型是开放的/可扩展的,而不是封闭的/exact https://github.com/microsoft/TypeScript/issues/12936。这允许接口扩展和类继承工作:
interface SuperHero extends Human {
powers: string[];
}
declare const captainStupendous: SuperHero;
describe(captainStupendous); // works, a SuperHero is a Human
你不会想要describe()
爆炸,因为你传入了SuperHero
,一种特殊类型的Human
额外powers
财产。所以不要使用Object.keys()
哪个正确地产生string[]
,您应该使用已知属性的硬编码列表,以便代码像describe()
将忽略任何额外的属性(如果存在)。
并且,如果您添加一个元素humanProps
,你会在你想要的地方看到错误describe()
将保持不变:
const humanProps = ["weight", "height", "age", "shoeSize"] as const; // added prop
const alice: Human = { // error!
age: 31,
height: 176,
weight: 47
};
const humanPropLabels: Readonly<Record<HumanProp, string>> = { // error!
weight: "Weight (kg)",
height: "Height (cm)",
age: "Age (full years)"
};
function describe(human: Human): string { // okay
let lines: string[] = [];
for (const key of humanProps) {
lines.push(`${humanPropLabels[key]}: ${human[key]}`);
}
return lines.join("\n");
}
好的,希望有帮助;祝你好运!
Playground 代码链接 https://www.typescriptlang.org/play/#code/HYQwtgpgzgDiDGEAEB5ANgEyQbwFBIPgHtgoAXJACwFcwRgAFAJyJiiQF4kBtAIgHcIASwDmlMrwA0SXpWFiJ03iBEReAXSQh2xUmQDc+AmQCeMZAAla9Zq05JT5ogDMq1xizbdgtAEYQmdUMCBzNLd3sAJQhiJgwAHis6D1ZpHzB-JgA+QyMkXXItNCFEAC4kJPp7PBCQlQhygGYARkk8kLlRcXLmgHYANjbagkEusnKAFl68gF99JFw8gooaZNsYABkQfzQocuiQDBI0E3jo2ITKlJhpciYhYBEsrOr2kflumQB1D4oACgA1iIAJRSN5UX7lXgWX5IP7wMCgobDepQgCCqjhzmoaDQSBMEBATCgoNmuRC2OA8DIQhISAw0Hg938f1W9HKV2B5TuDxEOHBaAgFGKwGg3LI90e3E0XGlwWGziITDhyyQAIgJiQLjca08JP5w1qIugADoYNQoJQ-gADAAk2DZ1y2Oyg3HVJnUM3K9sdbo1nutwPltRm4KYQuoTGASGNUBNACsiA8-rwADrAXhB2aLEIPMgBZwIZAAZWo5iYMJYSAgAA988AMOwrgbhjAiIJieLJSI5dmQgz4GgichVfAQDAyCAHsWyGWIA2iBbyqXy5WiMGGVAmUIWWOJ1PgDO5wuLUGkAB6c9IfhKgFQaQgJArgJrpBCdiPpIkXCh3CgSCwEWSAAHIQPwLb5CQhSOus7CygIvxSDInQKEhyiqGhlpEBAxZCAAXmomjaJBejBo44S6nYXDkdqMF6t4fgBEEeTkRUERcOcSqXO46xpIx2TkoQUEUCAxRlGxyTVBeV4BCwTAAITgqiSAtMitQoZ8fSDOCowKJM0whHMOZCXoOo2J4zoQLs+yEkcwAnGcMRcYkPGeLcEq8s8UmXtWTByYphq6Z8vA-GMcJAki4IaeMMgwmF8KImChrKbwGLIH82K4vihLEqShmCUglLUrS0abtuLKOhy7hckgPKPBBISCsKDxirVHlSjKPDMYairKvCwlqhqWquHRrD6jUhoELGZoWladoOq5rCWbsfoel6SA+u4q0Blmhqhoa4azlGMYtXGibJmmGa7QQoa-kAA