TypeScript中多函数通用参数的优雅处理方案问询
多引擎游戏函数的参数一致性实现方案探讨
我正在开发一款游戏,需要针对不同引擎实现功能等效的函数,且确保这些函数使用相同的默认参数。以下是我尝试的几种实现方式及其不足之处:
蛮力法
function frobnicateA(req: number, opt: number = 5) { console.log(req, opt) } frobnicateA(1, 2) function frobnicateB(req: number, opt: number = 5) { console.log(req, opt) } frobnicateB(1, 2)
- 调用时参数未命名,可读性差
- 不同实现间参数名无一致性强制,易出现差异
- 默认参数重复定义,维护成本高
常规法
(frobnicateB的实现类似,后续不再赘述)
interface Config { req: number opt?: number } function frobnicateA(cfg: Config) { let opt = cfg.opt ?? 5 console.log(cfg.req, opt) } frobnicateA({ req: 1, opt: 2 })
- 可选参数较多时,样板代码冗余
- 默认参数在各实现中重复定义
- 实现时可能遗漏参数默认值填充,导致逻辑错误
ES风格法
interface Config { req: number opt?: number } function frobnicateA({ req, opt = 5 }: Config) { console.log(req, opt) } frobnicateA({ req: 1, opt: 2 })
- 默认参数在各实现中重复定义,维护不便
- 遗漏默认参数赋值时,TypeScript无提示
接近理想法
interface Config { req: number opt?: number } const defaultOpt = 5 function frobnicateA({ req, opt = defaultOpt }: Config) { console.log(req, opt) } frobnicateA({ req: 1, opt: 2 })
- 遗漏默认参数赋值时无提示
- 写法不够简洁优雅
类封装法
class Config { req1!: number req2!: number opt: number = 5 constructor(cfg: Pick<Config, 'req1' | 'req2'> & Partial<Config>) { Object.assign(this, cfg) } } function frobnicateA(cfg: Config) { console.log(cfg.req1, cfg.req2, cfg.opt) } frobnicateA(new Config({ req1: 1, req2: 2, opt: 3 }))
- 构造函数设计晦涩,可读性差
Pick中重复声明必填参数,无强制校验机制- 函数调用需额外实例化
Config,操作繁琐
技巧法
type RequiredKeys<T> = { [K in keyof T]: T[K] extends Required<T>[K] ? K : never; }[keyof T]; type FillsAndOverrides<T> = Pick<T, RequiredKeys<T>> & Partial<T>; class Config{ req!: number opt?: number = 5 constructor(cfg: FillsAndOverrides<Config>){ Object.assign(this, cfg) } } function frobnicateA(cfg: Config){ console.log(cfg.req, cfg.opt) } frobnicateA(new Config({req:1, opt:2}))
- 函数调用需额外实例化
Config,操作繁琐 - 滥用
?作为RequiredKeys的筛选标记,逻辑不直观 - 直接调用
frobnicateA({ req: 1 })时无报错提示
填充函数法
interface Config { req: number opt?: number } function fillConfig(cfg: Config): Required<Config> { return { ...{ opt: 5 }, ...cfg }; } function frobnicateA(cfg: Config) { let fullCfg = fillConfig(cfg) console.log(fullCfg.req, fullCfg.opt) } frobnicateA({ req: 1, opt: 2 })
- 默认参数定义在填充函数中,位置隐蔽,不易查找
- 实现时遗漏调用
fillConfig,TypeScript无警告
调用端填充函数法
interface Config { req: number opt?: number } function fillConfig(cfg: Config): Required<Config> { return { ...{ opt: 5 }, ...cfg }; } function frobnicateA(cfg: Required<Config>) { console.log(cfg.req, cfg.opt) } frobnicateA(fillConfig({ req: 1, opt: 2 }))
- 默认参数定义位置隐蔽
- 参数填充逻辑应由函数自身完成,而非调用端处理
理想但不可行方案
parameters Config { req: number opt: number = 5 } function frobnicateA({req, opt}: Config) { console.log(req, opt) } frobnicateA({ req: 1, opt: 2 })
我知道有些要求过于挑剔,最终也可以选择上述任一方案,但总觉得应该存在一种更优雅、无上述问题的解决方案。
内容的提问来源于stack exchange,提问作者mqnc
相关产品推荐
相关产品推荐

