TypeScript:根据产品约束动态控制购买函数参数必填性
解决方案
核心思路是利用条件类型结合映射类型,为不同约束的产品生成精确的purchase函数类型,让TypeScript能自动推断调用时的参数要求。
1. 定义基础类型
先明确产品的类型结构,区分有无restrictions的产品:
// 定义约束类型示例,比如年龄限制 type AgeRequirement = { age: number }; // 产品类型映射,明确每个产品是否带约束 type Products = { soda: { name: string }; // 无约束产品 beer: { name: string; restrictions: AgeRequirement }; // 有约束产品 chips: { name: string }; // 无约束产品 };
2. 生成动态的Purchase函数类型
通过条件类型判断产品是否包含restrictions字段,决定purchase函数的参数要求:
// 针对单个产品类型,生成对应的purchase函数类型 type PurchaseFn<T extends keyof Products> = Products[T] extends { restrictions: infer R } ? (requirement: R) => void : () => void; // 定义返回的函数数组类型,绑定动态的purchase函数 type ItemFunctions<T extends keyof Products> = [ () => Products[T], // 获取产品信息的函数 () => void, // 示例其他函数(如view) PurchaseFn<T> // 带参数约束的purchase函数 ];
3. 改造getItem函数
用泛型绑定产品类型,让TypeScript能精准推断返回的purchase函数参数:
function getItem<T extends keyof Products>(productName: T): ItemFunctions<T> { return [ () => Products[productName], () => console.log(`Viewing ${productName}`), (requirement?: any) => { // 运行时根据产品是否有约束做分支处理 if ('restrictions' in Products[productName]) { console.log(`Purchasing ${productName} with requirement:`, requirement); } else { console.log(`Purchasing ${productName}`); } } ] as ItemFunctions<T>; }
4. 验证效果
现在调用时TypeScript会自动约束参数:
const [, , purchaseSoda] = getItem('soda'); purchaseSoda(); // ✅ 无需传参,正常通过 // purchaseSoda({ age: 18 }); ❌ 报错:不需要参数 const [, , purchaseBeer] = getItem('beer'); purchaseBeer({ age: 18 }); // ✅ 必须传参,正常通过 // purchaseBeer(); ❌ 报错:缺少必填参数
关键说明
- 条件类型
Products[T] extends { restrictions: infer R }会自动判断当前产品是否有约束字段,同时提取约束的具体类型R。 - 泛型
T extends keyof Products确保getItem的参数只能是预定义的产品名,避免非法输入。 - 运行时通过
'restrictions' in Products[productName]做分支处理,保证类型约束和运行逻辑一致。
内容的提问来源于stack exchange,提问作者Bogus Hawtsauce
相关产品推荐
相关产品推荐

