TypeScript中React useState允许接口外属性的问题咨询
问题解析:TypeScript useState允许额外属性的原因
你遇到的这个情况,核心是TypeScript的额外属性检查规则在起作用,和prevState的展开操作直接相关:
为什么help属性不报错?
TypeScript只会对直接传入的新鲜对象字面量触发额外属性检查——也就是当你直接写{ foo: 'a', bar: true, help: 'xxx' }这种没有经过任何变量引用的对象时,才会检查是否有接口外的属性。
但你的代码里,回调返回的是{...prevState, bar: true, help: 'why is this allowed?'}:
prevState是已有的ComponentState类型变量,展开它之后生成的对象,TypeScript会认为这是一个“非新鲜”的对象- 此时TypeScript只会验证这个对象是否兼容
ComponentState类型——也就是包含foo和bar两个必填属性,且类型匹配。只要满足这个条件,哪怕多了其他属性,TypeScript也不会报错,因为结构类型系统允许超类型赋值给子类型。
为什么修改bar的类型会报错?
bar在ComponentState里明确被定义为boolean类型,不管你是直接写字面量还是通过展开对象赋值,只要给bar传了非布尔值,就直接违反了类型约束,所以TypeScript会立刻报错——这属于基础的类型匹配校验,和额外属性检查是两套规则。
怎么避免这种潜在Bug?
如果想严格禁止额外属性,可以通过以下方式:
- 手动类型断言:强制让TypeScript检查返回值是否严格符合
ComponentState:setState((prevState) => ({ ...prevState, bar: true, help: 'why is this allowed?' } as ComponentState)); // 此时TypeScript会报错,提示`help`不属于ComponentState - 使用类型约束声明:先创建对象并指定类型,再返回:
setState((prevState) => { const newState: ComponentState = { ...prevState, bar: true, // help: 'xxx' 这里直接写会报错 }; return newState; });
关于useState的定义
你查看useState定义时没看到[key: string]: any是正常的——useState的类型约束只是要求返回值能赋值给泛型S(也就是ComponentState),而结构类型系统中,只要对象包含S的所有属性,就可以赋值,不管有没有额外属性。额外属性检查是TypeScript的一个额外校验机制,并非类型系统的核心规则。
内容的提问来源于stack exchange,提问作者Kevin Orriss
相关产品推荐
相关产品推荐

