ReactJS 和 Typescript :指的是一个值,但在此处用作类型(TS2749)

Ans*_*rer 31 validation typescript reactjs material-ui tsx

我在 .tsx 文件中使用 Typescript 和 Material-ui 编写 ReactJS 类。在我的自定义组件之一中,我想创建对我在自定义组件中使用的组件之一的引用。

export class MyTextField extends React.Component<MyProps, MyState> {
  private refTextField: React.RefObject<TextField>;
  constructor(props: MyProps) {
    super(props);
    this.refTextField = React.createRef();
  }

  render(): JSX.Element {
    const { id, label, value: defaultValue } = this.props;
    const { value } = this.state;
    const element = (
      <TextField ref={this.refTextField} id={id} label={label} defaultValue={defaultValue} value={value} />
    );

    return element;
  }
}
Run Code Online (Sandbox Code Playgroud)

在编译期间,我在引用的声明中收到错误消息:

'TextField' 指的是一个值,但在这里被用作一种类型。TS2749

我试图将“typeof TextField”放在我的声明中,但在我的渲染中评估 ref 属性时,我有另一条消息:

类型 'RefObject<(props: TextFieldProps) => Element>' 不能分配给类型 '((instance: HTMLDivElement | null) => void) | 引用对象 | 空| 不明确的'。类型 'RefObject<(props: TextFieldProps) => Element>' 不可分配给类型 'RefObject'。类型 '(props: TextFieldProps) => Element' 缺少类型 'HTMLDivElement' 中的以下属性:align、addEventListener、removeEventListener、accessKey 和 238 个更多。TS2322

有任何想法吗 ?太感谢了

jon*_*nyB 131

确保您使用的是 .tsx 文件而不是 .ts 文件

  • 这是人们应该检查的第一件事。 (21认同)

Jak*_*iel 45

将 * .ts文件更改为 * .tsx

在我的情况下它有效


Meh*_*kça 29

所以我之前在我的代码中多次遇到过这个问题,但直到今天才弄清楚发生这种情况的原因。

TL; DR 最后是问题的实际答案。

在 TypeScript 中创建类时,该类的名称既指实例类型又指 Javascript 类值。如果您将该类作为类型引用,TypeScript 会自动将其检测为该类的实例类型。如果您在运行时引用该类,它只是按照 Javascript 的含义使用它。直到现在,这一切都很好。

class MyClass {}
let abc: MyClass; // ts recognizes as instance type
abc = new MyClass(); // completely fine, used here as the javascript value
Run Code Online (Sandbox Code Playgroud)

但是,真正的问题是当您从模块动态导出类时。当你以某种方式导出类时,TypeScript 只能导出类的 Javascript 值,不会导出类型。因此,如果您将其导入另一个模块并尝试将其作为类型引用,您将获得 TS2749。

let intervariable = class MyClass{}
export const MyClass = intervariable; // TypeScript does not export type here.
Run Code Online (Sandbox Code Playgroud)
import {MyClass} from './myclass';

let abc: MyClass; // TypeScript error TS2749
Run Code Online (Sandbox Code Playgroud)

发生这种情况时,尤其是在您无法控制的情况下,我获取实例类型的解决方案只是使用 InstanceType 和 typeof:

import {MyClass} from './myclass';

let abc: InstanceType<typeof MyClass>; // no error
// the rest...
Run Code Online (Sandbox Code Playgroud)

typeof 运算符为您提供类值的类构造函数类型,InstanceType 泛型为您提供所需的实例类型。

TL;DR:在你的情况下,你只需要写InstanceType<typeof TextField>而不是TextField.

  • 我花了太多时间研究这个......谢谢。另一个见解是 Jest 管道与生产/开发管道完全不同...... (2认同)

Ini*_*asP 11

这应该是一个评论,但我没有足够的声誉。我想分享的是,使用已接受答案推荐的解决方案的一种干净方法是声明具有相同名称的类型别名(它不会导致冲突)。然后,您可以像通常使用实例类型一样使用您的类型。

添加到示例:

import {MyClass} from './myclass';

type MyClass = InstanceType<typeof MyClass>;

let abc: MyClass; // still no error!
Run Code Online (Sandbox Code Playgroud)

编辑:类型导入似乎也可以工作,而且看起来更干净:

import type {MyClass} from './myclass';
Run Code Online (Sandbox Code Playgroud)

该方法的警告import type是您不能将其用作值(例如构造new MyClass(...))。