如何实现基于数据是否为空的TypeScript函数可选参数类型推断
TypeScript 条件可选参数与类型兼容问题解决方案
问题背景
需要实现两个核心逻辑:
- 当调用目标Key对应的Data为空对象(判断条件:
keyof Data extends never)时,可省略第二个参数(或对象中的params属性) - 当Data非空时,必须传入对应的参数(或params属性)
现有两个实现都存在问题:
infer函数调用infer("post")时提示参数数量不足infer2函数传入post并携带params: {}时出现类型不兼容错误
方案一:修复多参数形式的infer函数
利用泛型条件类型结合剩余参数,让第二个参数根据Data是否为空动态变为可选:
type MappedData = { user: { name: string; }; post: {}; }; function infer<Key extends keyof MappedData>( key: Key, ...args: keyof MappedData[Key] extends never ? [] : [data: MappedData[Key]] ): void {} // 验证调用 infer("user", { name: "Ryan" }); // ✅ 正常,必须传入第二个参数 infer("post"); // ✅ 正常,可省略第二个参数 infer("post", {}); // ✅ 允许传入空对象(符合需求) infer("user"); // ❌ 报错:缺少必需的第二个参数,符合预期
也可以用函数重载实现更直观的约束:
// 重载签名:post类型可省略参数 function infer(key: "post"): void; // 重载签名:其他非空Data类型必须传第二个参数 function infer<Key extends Exclude<keyof MappedData, "post">>(key: Key, data: MappedData[Key]): void; // 实现签名 function infer<Key extends keyof MappedData>(key: Key, data?: MappedData[Key]) { // 业务逻辑实现 }
方案二:修复单参数对象形式的infer2函数
调整ExtractData类型,让空Data对应的params属性变为可选且类型匹配,同时保留非空Data时params的必填约束:
type MappedData = { user: { name: string; }; post: {}; }; type ExtractData<Key extends keyof MappedData> = keyof MappedData[Key] extends never ? { key: Key; params?: MappedData[Key] } // 空Data时params可选 : { key: Key; params: MappedData[Key] }; // 非空Data时params必填 function infer2<Key extends keyof MappedData>(o: ExtractData<Key>) {} // 验证调用 infer2({ key: "user", params: { name: "Ryan" } }); // ✅ 正常 infer2({ key: "post", params: {} }); // ✅ 正常,不再报类型不兼容错误 infer2({ key: "post" }); // ✅ 正常 infer2({ key: "user" }); // ❌ 报错:缺少必填的params属性,符合预期
内容的提问来源于stack exchange,提问作者Ryan Izac
相关产品推荐
相关产品推荐

