ts循环赋值断言也报错?-灵析社区

我爱上班

挺有意思的一个问题。 首先要指出,题主这种写法,在 TS 3.4 之前是不会报错的。而在 TS 3.5 之后引入了一项名为 [Fixes to Unsound Writes to Indexed Access Types](https://link.segmentfault.com/?enc=C7ijwGKrq6jAIdi734Cjfw%3D%3D.RwL1N1h2X2jNOf%2BP1XxQzerDaCiwG6s8hjCtYmampklg1XTxc6iv%2Bw6UXgQnTjyHKDIEFXyr%2FeFB%2BzSiIDIrJVy1MX%2B%2FfvOJmgsWqXPOv8Fr1Oua3e9nlHUMjnrUqaCWjnfPJGpp13pGcDiayvR%2FsA%3D%3D) 的破坏性变更后,才会报错。 相关的讨论有很多,比如 [#30769](https://link.segmentfault.com/?enc=r1XpR1vXVQfOWT7qBzupTg%3D%3D.5vrc9tZrSLK%2BkeCAqKtmjRCyaUI8BxXgdK%2Bus3qICGpkYrWnmS1SnnFQfGDg%2BcYGEwylx34RA9DnF45lCL7%2FbQ%3D%3D)、[#33834](https://link.segmentfault.com/?enc=0i0Gl1Sot7KV6LgadjfKgA%3D%3D.4uDkaD9XlN0j%2F2zIZuxpbp13UwjGFx3yESgHO4TlJvGCJEe7%2FYIBkr4bCPwvM4u%2BYsCuUxnceA1ZVfdZjWf29Q%3D%3D)。 那么为什么 TS 要把这种写法视为一种错误呢? 其实如果你只是取值(即 Read),是没问题的: let v = obj[key as keyof PersonType]; // ok 此时 `v` 的类型会推断为 `string | number`,也就是 `PersonType` 中**所有属性的联合类型** 。 问题出现在赋值(即 Write)上。 我们可以看出,其实 `PersonType` 上每个属性的类型,是确定的,要么是 `string`、要么是 `number`,并不真的存在一个属性的类型是 `string | number`。因此我们在尝试下面的写法时,才会得到错误,这是符合预期的: person.name = 16; // error person.age = '曜'; // error 但如果你用了索引属性去赋值,那么就会出现: let key = 'name'; person[key as keyof PersonType] = 16; let key = 'age'; person[key as keyof PersonType] = '曜'; 就打破了上面这种预期,也就是所谓的 **Unsound Writes** 。 因此 TS 3.5 之后引入了这项破坏性变化,当你尝试这么做的时候,会把类型收窄为**所有属性的交叉类型** ,只有满足此交叉类型的,才能正确赋值。具体到本题中得到的交叉类型也就是 `string & number`,但很显然,没有任何类型 `T` 是能满足 `T extends string & number` 的,因此得到了 `never`,故而抛出题中的异常。 * * * 改法有很多种,但我只推荐用泛型。 除非你这个 `cloneObj` 专门针对 `PersonType` 编写的,否则我建议你这么写: function cloneObj>(obj: T) { const newObj = {} as T; for (const key of Object.keys(obj)) { newObj[key as keyof T] = obj[key as keyof T]; } return newObj; }

阅读量:1

点赞量:0

问AI