为何TypeScript在解构时无法推断可区分联合类型?
解构可区分联合类型时无法自动收窄的原因及解决办法
你遇到的问题是解构参数后,TypeScript无法通过readonly字段的判断来收窄剩余props的类型,这并非代码错误,而是对TypeScript 4.4版本特性的理解偏差。
原因分析
TypeScript 4.4确实增强了联合类型的收窄能力,但这种增强是针对同一对象的属性访问的。当你在函数参数里直接解构{ readonly, ...props }时,readonly和props会被视为两个独立的变量——TypeScript无法追踪到这两个变量原本来自同一个联合类型的对象,自然也就无法通过readonly的值来推导props的类型。
而在第二种写法中,你先对整个props进行类型收窄(通过props.readonly判断),此时props的类型已经被确定为Readonly或Writable,再解构出剩余属性时,TypeScript能正确推断出剩余属性的类型就是对应的ReadonlyRecord或WritableRecord。
解决方案
如果想保留参数解构的写法,可以通过以下方式实现:
方法1:使用类型断言
const fn: Fn = ({ readonly, ...props }) => { switch (readonly) { case true: const readonlyCheck: ReadonlyRecord = props as ReadonlyRecord break; case false: const writableCheck: WritableRecord = props as WritableRecord break } }
方法2:自定义类型守卫
先定义类型守卫函数来判断剩余props的类型:
function isReadonlyRecord(props: WritableRecord | ReadonlyRecord): props is ReadonlyRecord { return 'otherField' in props; } function isWritableRecord(props: WritableRecord | ReadonlyRecord): props is WritableRecord { return 'someField' in props; } const fn: Fn = ({ readonly, ...props }) => { switch (readonly) { case true: if (isReadonlyRecord(props)) { const readonlyCheck: ReadonlyRecord = props; } break; case false: if (isWritableRecord(props)) { const writableCheck: WritableRecord = props; } break } }
方法3:先收窄整体类型再解构(验证可行的写法)
这种写法最安全,不需要额外断言或类型守卫,也是TypeScript推荐的方式:
const fn: Fn = (props) => { switch (props.readonly) { case true: const { readonly, ...readonlyProps } = props const readonlyCheck: ReadonlyRecord = readonlyProps break; case false: const { readonly, ...writableProps } = props const writableCheck: WritableRecord = writableProps break; } }
内容的提问来源于stack exchange,提问作者vyenkv
相关产品推荐
相关产品推荐

