如何在TypeScript中约束recipes属性值为ingredients的合法键名
解决TypeScript中recipes数组元素必须匹配ingredients键的问题
要让recipes里的数组元素严格对应ingredients的键名,核心是利用TypeScript的键类型推导和泛型来约束类型,以下是两种可行方案:
方案一:泛型通用型定义
把CookBook定义为泛型类型,让它动态捕获ingredients的键集合,这样recipes的数组元素就会被限制为这些键:
// 泛型CookBook类型,IngredientKeys约束为字符串类型 type CookBook<IngredientKeys extends string> = { ingredients: Record<IngredientKeys, { vegetal: boolean }>, recipes: { [key: string]: IngredientKeys[] } } // 定义时无需手动指定泛型,TypeScript会自动推导ingredients的键 const cookbook = { ingredients: { "tomato": { vegetal: true }, "cheese": { vegetal: false }, "lettuce": { vegetal: true }, }, recipes: { "pizza": ["tomato", "cheese"], "salad": ["tomato", "lettuce"] } } satisfies CookBook<string>;
当你在recipes里加入非ingredients的键(比如"pineapple"),TypeScript会直接抛出类型错误:
// 错误示例:"pineapple"不在ingredients的键集合中 const invalidCookbook = { ingredients: { "tomato": { vegetal: true }, "cheese": { vegetal: false }, "lettuce": { vegetal: true }, }, recipes: { "pizza": ["tomato", "cheese", "pineapple"] // 此处报错 } } satisfies CookBook<string>;
方案二:基于现有ingredients推导键类型
如果你的ingredients结构固定,可以先单独定义它,再通过keyof typeof推导键类型,直接约束recipes:
// 先定义具体的ingredients对象 const ingredients = { "tomato": { vegetal: true }, "cheese": { vegetal: false }, "lettuce": { vegetal: true }, }; // 推导ingredients的键类型 type IngredientKey = keyof typeof ingredients; // 定义CookBook类型,recipes数组元素必须是IngredientKey type CookBook = { ingredients: typeof ingredients, recipes: { [key: string]: IngredientKey[] } }; // 定义cookbook时自动触发类型检查 const cookbook: CookBook = { ingredients, recipes: { "pizza": ["tomato", "cheese"], "salad": ["tomato", "lettuce"] } };
同样,当recipes出现非法键时会立即报错,完美符合你的需求。
内容的提问来源于stack exchange,提问作者UXK
相关产品推荐
相关产品推荐

