升级React与ReactDOM到16.3.2后,getBoundingClientRect出现类型编译错误
getBoundingClientRect的类型错误问题 我刚帮你梳理清楚这个问题的核心:React 16.3+对ReactDOM.findDOMNode的类型定义做了更严格的约束——它的返回值从原来的Element扩展成了Element | Text | null,而Text节点并没有getBoundingClientRect方法,所以TypeScript直接抛出了类型不匹配的错误。
下面给你几个靠谱的解决办法,按推荐程度排序:
1. 改用React.createRef(官方推荐方案)
从React 16.3开始,官方更建议用createRef获取DOM节点,不仅类型更明确,还符合组件封装的最佳实践,也能彻底规避这个类型问题。
修改步骤很简单:
- 先在组件类中创建指定类型的ref:
class YourDropdownComponent extends React.Component { // 替换成你实际使用的容器元素类型,比如HTMLDivElement/HTMLButtonElement containerRef = React.createRef<HTMLDivElement>(); // ...组件其他逻辑 }
- 在render阶段给容器元素绑定这个ref:
render() { return <div ref={this.containerRef} className="dropdown-container"> {/* 组件内容 */} </div>; }
- 最后获取节点并调用方法:
const node = this.containerRef.current; if (!node) { return; } const rect = node.getBoundingClientRect(); // 后续展开方向判断逻辑
这种方式不需要额外的类型校验,ref的current会被明确限定为你指定的元素类型,TypeScript会直接通过检查。
2. 添加类型守卫(兼容现有findDOMNode代码)
如果你暂时不想改动findDOMNode的用法,可以通过类型守卫来确保节点是Element类型:
const node = ReactDOM.findDOMNode(this.containerElement); // 同时判断节点存在且是Element类型 if (!node || !(node instanceof Element)) { return; } const rect = node.getBoundingClientRect(); // 后续处理逻辑
这里node instanceof Element会让TypeScript明确知道,进入代码块后node肯定是拥有getBoundingClientRect方法的Element类型,错误自然就消失了。
3. 类型断言(快速但需谨慎)
如果你能100%确定this.containerElement对应的DOM节点一定是Element而非Text,可以直接用类型断言跳过检查:
const node = ReactDOM.findDOMNode(this.containerElement) as Element; if (!node) { return; } const rect = node.getBoundingClientRect();
不过这种方式有风险——如果后续代码变更导致节点类型变成Text,TypeScript不会再帮你做校验,可能会引发运行时错误,所以只推荐在场景非常明确的情况下使用。
额外提一句:React官方其实不太推荐使用findDOMNode,因为它会打破组件的封装性,而且在未来版本中有被废弃的可能,所以优先考虑第一种createRef的方案会更稳妥。
内容的提问来源于stack exchange,提问作者farzad

