问题的背景:在 JavaScript 中,函数经常在签名中直接使用对象解构。在 TypeScript 中,这种方法需要明确描述被解构参数的结构,并设置默认值 - 否则可能在访问不存在的属性时出现错误,并导致类型推导不正确。
问题:如何正确描述整个参数或被解构对象中单独嵌套属性的类型,特别是在存在可选和嵌套字段以及默认值时。
解决方案:始终为函数参数的结构描述单独的类型或接口,明确指出哪些字段是必需的,哪些是可选的,默认值应在函数体内或直接在参数中使用 ES6 语法进行设置。
代码示例:
interface UserOptions { name: string; age?: number; address?: { city: string; zipcode?: string }; } function registerUser( { name, age = 18, address = { city: 'Unknown' } }: UserOptions ): string { return `${name}, ${age}, ${address.city}`; }
关键要点:
可以忽略参数对象的类型描述 - 依赖自动推导吗?
不可以,这样很危险。如果不指定 UserOptions 的类型,编译器将不会提示必需的属性,默认值不会被提取到嵌套字段,并将在使用阶段出现隐性错误。
function example({ x, y }) { ... } // x 和 y 是 any
如何为嵌套对象设置默认值,部分替换属性?
使用扩展操作符。但如果 address 是可选的,扩展不会“合并”类型。需要进行检查或明确设置默认值。
function fn({ obj = { foo: 1 } }: { obj?: { foo: number } }) { const address = { foo: 42, ...obj }; }
没有默认值的可选字段的解构有什么危险?
如果不为可选属性设置默认值,访问属性(例如,address.city)可能导致运行时错误。最好明确设置 ? 和默认值。
function danger({ address }: { address?: { city: string } }) { console.log(address.city); // 错误,address 可能是 undefined }
在旧代码中对参数对象进行了没有明确类型化的解构。当在函数中添加新字段时,所有使用场合没有被自动找到,导致生产环境中的调用失败。
优点:
缺点:
为所有此类函数引入了接口,使用测试覆盖了 undefined 和默认值场景,编译器的提示使得进行大规模更改变得容易。
优点:
缺点: