Flow 为何不允许将含更多属性的泛型传递给期望更少属性的子组件
报错根因
Flow对泛型类型的默认型变规则是 不变(invariant):
默认场景下,哪怕Form<MyData>的结构完全覆盖Form<MyOtherData>的所有可用属性,Flow也不会自动判定两者兼容,要求泛型参数的结构必须和声明完全一致。
给所有属性加上$ReadOnly标注无法改变这个默认行为——只读标记仅限制属性不能被修改,没有给泛型属性声明协变方向,Flow依然会对泛型参数做严格的一致性校验,最终抛出prop-missing类的不兼容报错。
解决方案
当前场景完全符合 协变(covariant) 的适用条件:Form内部的data属性是只读的,下游组件不会对其执行写操作,可以通过给属性加协变标记,实现预期的结构兼容传递效果。
协变标记的规则是:在对象属性前加+符号,声明该位置的类型支持子类型向父类型的自动匹配——也就是允许把带更多属性的泛型实例,传递给要求带更少属性的泛型参数的场景。
修改后的Form类型定义:
export type Form<T: $ReadOnly<{}> = {}> = $ReadOnly<{ +data: $ReadOnly<T>, }>
修改后Flow会自动完成兼容判定:
- 带
cool和superCool属性的MyData结构,是仅带cool属性的MyOtherData的子类型 - 因为
data是协变位置,Form<MyData>自然成为Form<MyOtherData>的子类型,可以直接传递给下游接收Form<MyOtherData>的组件,不会再抛出多余属性的报错。
注意事项
- 协变标记仅适合搭配只读属性使用:如果
Form类型存在可以修改data的方法或属性,贸然加协变会破坏类型安全——比如下游组件误将data赋值为缺少额外属性的对象,就会导致上游持有的原对象类型标注和实际结构不一致。当前全只读的场景下,加协变不存在安全风险。 - 不需要对传递的对象做额外的类型转换,只要修正泛型的型变标记,Flow就会按照结构子类型的规则自动完成兼容校验。
内容的提问来源于stack exchange,提问作者Danielo515
相关产品推荐
相关产品推荐

