You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

为何使用展开语法向组件传props时TypeScript未检出多余属性错误?

为什么通过展开语句向组件传递props时,TypeScript的类型校验会失效?

问题复现

以下方代码为例,我们给Props仅定义了someTitle字段的组件,通过展开语法传入了额外的TICK属性,但TS和linter都没有抛出类型错误:

type SomeComponentProps = Readonly<{
  someTitle: string
}>

const SomeComponent = ({ someTitle }: SomeComponentProps) => {
  return <>someTitle</>
}

const MainComponent = () => {
  const someTitle = 'Some title'
  const TICK = 'TICK'

  return <SomeComponent {...{ someTitle, TICK }} />
}

核心原因

你期待的「传入未定义的Props就报错」的能力,来自TS的多余属性检查(Excess Property Checks),这是一个特殊的语法校验规则,不属于TS结构化类型系统的默认逻辑,它只会在非常窄的场景下触发:

  • 只有当你直接把对象字面量赋值给明确标注类型的变量,或者直接把对象字面量作为参数传给明确标注类型的形参时,TS才会检查对象里有没有多余的、目标类型没定义的字段,存在就报错。

而JSX里的展开传参,刚好绕开了这个检查的触发条件:

  1. 你写的{...{ someTitle, TICK }}里,内层的对象字面量没有被直接标注为SomeComponentProps类型,TS会先把它推导成一个独立的匿名类型:{ someTitle: string; TICK: string }
  2. 接下来TS只会做通用的结构化类型兼容性校验:检查这个匿名类型是不是满足SomeComponentProps的所有要求——也就是有没有类型为string的someTitle字段。检查通过就判定类型合法,不会额外管多出来的TICK字段。
  3. 结构化类型系统本身不禁止源类型比目标类型多字段,只要目标类型要求的字段都存在、类型匹配,就认为类型兼容。

怎么让展开传参也触发多余属性校验

只要把要展开的对象提前显式标注为组件的Props类型,多余属性检查就会在对象定义的位置触发:

const MainComponent = () => {
  const someTitle = 'Some title'
  const TICK = 'TICK'
  // 这里显式标注类型,写TICK字段时TS会直接报错:对象字面量中存在多余属性TICK
  const componentProps: SomeComponentProps = { someTitle, TICK }

  return <SomeComponent {...componentProps} />
}

作为对比,如果你不通过展开,直接在JSX标签上写属性(比如<SomeComponent someTitle="xx" TICK="TICK" />),TS会直接报错,因为这种写法刚好符合多余属性检查的触发条件,相当于直接把属性组成的对象字面量绑定到了Props类型的位置。

内容的提问来源于stack exchange,提问作者Timur Zakirov

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.27 12:06:20