
本文介绍在 typescript 中如何定义函数参数,使其仅接受某个对象中特定类型(如 number)的若干属性名,实现类型安全的动态属性访问。
本文介绍在 typescript 中如何定义函数参数,使其仅接受某个对象中特定类型(如 number)的若干属性名,实现类型安全的动态属性访问。
在开发中,我们常需编写通用函数来根据传入的属性名动态读取对象字段(例如计算 priceNet * quantity 或 priceGross * quantity)。但若仅用 keyof Article,类型系统无法排除 name(string)等不兼容类型,导致运行时错误或类型不安全。此时需结合联合字面量类型与交集类型(&),精准收窄键的取值范围。
✅ 正确的类型定义方式
核心思路是:先限定键必须属于 Article 的键集合(keyof Article),再进一步约束其必须是 "priceNet" 或 "priceGross" 之一——这可通过交集类型 keyof Article & ("priceNet" | "priceGross") 实现。TypeScript 会自动推导出该类型既是合法键,又具备 number 类型值(因 Article["priceNet"] 和 Article["priceGross"] 均为 number)。
type Article = {
name: string;
quantity: number;
priceNet: number;
priceGross: number;
};
function summarise(
article: Article,
priceTypeProperty: keyof Article & ("priceNet" | "priceGross")
): number {
return article[priceTypeProperty] * article.quantity;
}✅ 调用示例(全部通过类型检查):
const myArticle: Article = {
name: "Laptop",
quantity: 3,
priceNet: 999.99,
priceGross: 1199.99
};
summarise(myArticle, "priceNet"); // ✅ 返回 number
summarise(myArticle, "priceGross"); // ✅ 返回 number❌ 错误调用将被严格拦截:
summarise(myArticle, "name"); // ❌ Type '"name"' is not assignable to type '"priceNet" | "priceGross"' summarise(myArticle, "otherPrice"); // ❌ Property 'otherPrice' does not exist in type 'Article' summarise(myArticle, "quantity"); // ❌ Type '"quantity"' is not assignable to type '"priceNet" | "priceGross"'
⚠️ 注意事项与进阶建议
不要使用 string 或 keyof Article 单独作为类型:前者完全失去类型保护,后者允许任意属性(如 name),可能引发 string * number 运行时 NaN。
交集类型 & 是关键:keyof Article & ("priceNet" | "priceGross") 利用了 TypeScript 的类型交集规则——只有同时满足“是 Article 的键”且“属于该联合字面量”的字符串才被允许。
-
可提取为复用类型别名(提升可维护性):
type PriceField = "priceNet" | "priceGross"; type NumericPriceKey = keyof Article & PriceField; function summarise(article: Article, priceTypeProperty: NumericPriceKey) { ... } 若属性名需动态扩展(如新增 priceWholesale),只需更新联合类型 PriceField,所有依赖处将自动获得类型提示与校验。
通过这种声明式、组合式的类型定义,你能在保持代码灵活性的同时,获得编译期 100% 的类型安全保障——这才是 TypeScript 类型系统的核心价值所在。










