TypeScript枚举对应payload为undefined时如何省略第二个参数
TypeScript 条件入参可选实现方案
问题复现
原有实现中,即使在SubstitutionsMap中将枚举键对应的类型设为undefined,调用函数时仍被强制要求传入第二个参数,省略时抛出ts(2554)错误:
export enum MyKey { BleepBloop = 'BleepBloop', BeepBoop = 'BeepBoop', BingBong = 'BingBong', } export type SubstitutionsMap = { [MyKey.BleepBloop]: [string, string]; [MyKey.BeepBoop]: [string, string]; [MyKey.BingBong]: undefined; }; export const getFoo = <K extends MyKey>(key: K, substitutions: SubstitutionsMap[K]): string => { // 内部逻辑 return '' }; getFoo(MyKey.BingBong) // 抛出ts(2554):Expected 2 arguments, but got 1.
错误原因
TypeScript 中参数类型为undefined不代表参数可以省略,只有显式标记为可选参数(参数名后加?)、或者通过rest元组类型允许空入参时,才可以不传对应位置的参数。原有实现中substitutions是必填位置参数,因此即使类型为undefined也必须显式传入。
实现方案
方案1:函数重载(类型提示最友好)
通过重载签名分别定义需要传参和不需要传参的调用形式,实现签名中将第二个参数标记为可选,兼顾类型校验和调用便捷性:
// 不需要传第二个参数的调用签名 export function getFoo(key: MyKey.BingBong): string; // 需要传第二个参数的调用签名 export function getFoo<K extends Exclude<MyKey, MyKey.BingBong>>( key: K, substitutions: SubstitutionsMap[K] ): string; // 函数实现 export function getFoo<K extends MyKey>(key: K, substitutions?: SubstitutionsMap[K]): string { // 内部可通过key值做类型收窄 if (key === MyKey.BingBong) { // 此分支下substitutions为undefined类型 } else { // 此分支下substitutions为对应元组类型 } return '' }; // 调用校验 getFoo(MyKey.BingBong) // 正常通过 getFoo(MyKey.BeepBoop, ['a', 'b']) // 正常通过 getFoo(MyKey.BeepBoop) // 抛出错误:缺少第二个参数 getFoo(MyKey.BingBong, undefined) // 也兼容原有写法
方案2:条件类型+Rest参数(扩展性更好)
如果后续有多个不需要传第二个参数的枚举键,可以通过条件类型自动判断参数是否可选,不需要每次新增key都加重载签名:
export const getFoo = <K extends MyKey>( key: K, ...[substitutions]: SubstitutionsMap[K] extends undefined ? [] | [undefined] : [SubstitutionsMap[K]] ): string => { // 内部逻辑 return '' };
该写法的逻辑是:当当前key对应的映射类型为undefined时,rest参数允许空元组(即不传第二个参数)或者传入单个undefined值;如果对应类型不是undefined,则要求必须传入一个匹配类型的参数。后续新增无参key时,只需要在SubstitutionsMap中将对应值设为undefined即可,不需要修改函数定义。
内容的提问来源于stack exchange,提问作者javascwipt
相关产品推荐
相关产品推荐

