我只是被运行时异常咬住了,因为我将React ref传递给了错误的组件。
我想知道TypeScript是否可以在这里保存我的培根?
精简测试用例:
import * as React from 'react';
class Modal extends React.Component<{}> {
close = () => {};
}
declare const modal: Modal;
modal.close();
const modalRef = React.createRef<Modal>();
// Let's try giving this ref to the correct component…
// No error as expected :-)
<Modal ref={modalRef} />;
class SomeOtherComponent extends React.Component<{}> {}
// Let's try giving this ref to the wrong component…
// Expected type error but got none! :-(
<SomeOtherComponent ref={modalRef} />;
// Now when we try to use this ref, TypeScript tells us it's safe to do so.
// But it's not, because the ref has been incorrectly assigned to another component!
if (modalRef.current !== null) {
modalRef.current.close() // runtime error!
}
答案 0 :(得分:1)
之所以没有在ref上出现任何错误,是因为您的示例中两个组件都是同一基类 React.Component 的派生类,但它们却没有任何不同的属性,并且没有明确的界面。
在Typescript中检查有关类型兼容性的部分: https://www.typescriptlang.org/docs/handbook/type-compatibility.html
由于Typescript使用结构化子类型而不是名义子类型,因此在以下情况下可以合并类并进行相等比较:
在所有其他情况下,它们都不兼容。
以防您重写为:
React.createRef<HTMLInputElement>();
例如,您将清楚地看到引用在组件上被概述为不兼容。
这是因为React.Component与HTMLElement类型不兼容(HTMLInputElement是派生的,例如这些类具有不同的属性)。
并不是说这个断言不起作用,更多的是它在幕后如何精确运作的情况,这遵循上面概述的规则。
回到当前问题
您可以根据自己的情况采取多种措施来避免此类问题,
您有2个组成部分,具有不同的反应道具。
如果您的组件具有不同的道具,请为两者创建接口,并且不会出现此问题,因为它将返回类型错误,这些组件上的道具不匹配,这是正确的。
您有2个组件,没有自定义react属性
您当前的问题。如果您将新的属性成员添加到 Modal 类中不存在的 SomeOtherComponent 中,例如open = () =>
,则它们将被解析为不同的属性。
摘要
如果您无法添加接口,并且在这两个类中没有不同的属性成员,那么这是同一类就足够现实了。
您只需要找到一种在两种情况下都可以使用的更好方法。
答案 1 :(得分:-1)
可能的解决方案是为类和引用使用接口。
interface IModal {
close(): void;
}
class Modal extends React.Component<{}> implements IModal {
close = () => {};
}
const modalRef = React.createRef<IModal>();
<Modal ref={modalRef as React.RefObject<Modal>}/>
<SomeOtherComponent ref={modalRef} />
// Type 'RefObject<IModal>' is not assignable to type 'string | ((instance: //SomeOtherComponent | null) => void) | RefObject<SomeOtherComponent> | null | undefined'.
// Type 'RefObject<IModal>' is not assignable to type 'RefObject<SomeOtherComponent>'.
// Type 'IModal' is missing the following properties from type 'SomeOtherComponent': render, context, setState, forceUpdate, and 3 more. TS2322