版本是 15,所以没法用 React.createRef 所以写了 callback ref,但是一旦想抽成组件内部函数怎么写都写不对
class A extends Component<{}, {}> {
createRef = (element: HTMLDivElement | null) => this.rootElement = element
render() {
return (
<B ref={this.createRef}/>
)
}
}
type Bprops = {
ref: React.Ref<HTMLDivElement>
}
class B extends Component<Bprops> {
render() {
const {ref} = this.props
return <div ref={ref}/>
}
}
然后就报错
TS2322: Type '(element: HTMLDivElement | null) => HTMLDivElement | null' is not assignable to type '(Ref<PopUpAd> | undefined) & Ref<HTMLDivElement>'. Type '(element: HTMLDivElement | null) => HTMLDivElement | null' is not assignable to type 'string & ((instance: HTMLDivElement | null) => any)'. Type '(element: HTMLDivElement | null) => HTMLDivElement | null' is not assignable to type 'string'.
完全不知道报错的这些东西哪来的,react 的定义里就一句
type Ref<T> = string | { bivarianceHack(instance: T | null): any }["bivarianceHack"];
而且定义里的 string 是或,而报错里的是交
想去掉报错只能把 createRef
的参数的类型声明去掉,实际上就相当于是 any 把
1
2i2Re2PLMaDnghL 2021-09-07 10:23:50 +08:00 1
我先解释下报错里的交,为写得段我就把 PopUpAd 和 HTMLDivElement 写成 A 和 B 了
(Ref<A> | undefined) & Ref<B> = (Ref<A> & Ref<B>) | (undefined & Ref<B>) // 分配律 = Ref<A> & Ref<B> // undefined 交非 undefined 任何为空 = (string | (A|null) => any) & (string | (B|null) => any) // Ref<T> 展开 = (string & string) | (((A|null) => any) & string) | (string & ((B|null) => any)) | (((A|null) => any) & ((B|null) => any)) // 分配律 |
2
2i2Re2PLMaDnghL 2021-09-07 10:30:42 +08:00 1
你这边 (Ref<PopUpAd> | undefined) & Ref<HTMLDivElement> 在不考虑二者有包含关系的情况下就只能是 string 了。
再考虑到 Ref<T> 对 T 逆变,也可以是 Ref<PopUpAd | HTMLDivElement> ?这个部分我验算算不清。 也就是说你的 createRef 应当符合 (PopUpAd | HTMLDivElement | null) => any 至于 PopUpAd 是哪来的,我就没有头绪了 |
3
Leviathann OP @2i2Re2PLMaDnghL 额,忘了改报错信息
PopUpAd 就是这里的 B 组件 也就是说 A 组件想要持有一个 B 组件中某个 HTMLElement 的 ref 那 A 组件的持有的 ref 就要定义为 HTMLElement | B | null 吗 |
4
2i2Re2PLMaDnghL 2021-09-07 20:40:46 +08:00
或者公共父类。看上去 Component 就可以了?
猜想, 因为你的 createRef 传送过程中先后通过了 B.ref 和 Div.ref ,所以必须都符合。 ```<B ref={this.createRef}/>``` 这一段可能检查引擎蕴含了 createRef 必须是 Ref<B>,或者说 Component 的定义里包含了这一限定,你的 Bprops 实际是与之相交而非覆盖。 你尝试下把这个 ref 的名字改成 myref 试试? 当然理论上也可以让 B 同时 extends Div,但引入的问题可能比解决的多。 然后发现其实是双变的,bivarianceHack 这名字看上去就是为了让 TS 允许双变,不清楚如何办到的。范畴论推理不是我的强项。 |