如何实现TypeScript函数输入对象键依赖其他键值的静态类型?
TypeScript 根据字段值约束对象键的实现方案
问题描述
需要实现一个函数,其输入对象的字段需根据method的值做静态类型约束:仅当method为URL类型时允许headers字段,否则禁止该字段。同时要求函数返回值能正确推断输入的类型。当前代码无法实现该约束(传入method: 'memory'时仍能添加headers字段而不报错),希望找到比Exact类型助手更简单的解决方案。
原代码问题分析
原代码中泛型参数$Input extends Input<URL | 'memory'>的写法存在缺陷:TypeScript的结构类型系统允许包含额外属性的对象赋值给兼容类型,且泛型参数会被推断为包含额外属性的类型(如{ method: 'memory', headers: {} }),该类型仍满足extends Input<'memory'>的条件,因此无法触发错误。
简化解决方案
通过将泛型参数约束为method的类型(而非整个输入对象的类型),让TypeScript对method的每个可能分支单独做类型检查,从而实现精确约束:
export type Input<$Method extends URL | 'memory'> = { method: $Method } & ($Method extends URL ? { headers?: HeadersInit } : {}) // 泛型参数约束为method的类型,输入直接使用Input<$Method> declare const foo: <$Method extends URL | 'memory'>(input: Input<$Method>) => Input<$Method> // 合法调用 foo({ method: new URL('http://abc'), headers: {} }) foo({ method: new URL('http://abc') }) foo({ method: 'memory' }) // @ts-expect-error headers字段在method为'memory'时被禁止 foo({ method: 'memory', headers:{} })
方案说明
- 类型推断逻辑:调用函数时,TypeScript会先推断
$Method的具体类型(URL或'memory'),再检查输入是否匹配Input<$Method>的结构。 - 额外属性检查:当传入对象字面量时,若包含
Input<$Method>中没有的字段(如method: 'memory'时的headers),TypeScript会触发对象字面量额外属性检查,直接报错。 - 返回值类型:返回值
Input<$Method>会自动匹配输入的类型,确保类型推断准确。
若需要更严格的约束(比如禁止非字面量对象携带额外属性),可以结合Omit或精确类型,但上述方案已满足核心需求,且实现更简洁。
内容的提问来源于stack exchange,提问作者Jason Kuhrt
相关产品推荐
相关产品推荐

