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

ReactJS and Typescript : refers to a value, but is being used as a type here (TS2749)

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

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;
  }
}

在编译过程中,我的引用声明出现错误:

'TextField' refers to a value, but is being used as a type here. TS2749

我试图将 "typeof TextField" 放入我的声明中,但我收到另一条消息,当 valuing 在我的渲染中引用 属性 时:

Type 'RefObject<(props: TextFieldProps) => Element>' is not assignable to type '((instance: HTMLDivElement | null) => void) | RefObject | null | undefined'. Type 'RefObject<(props: TextFieldProps) => Element>' is not assignable to type 'RefObject'. Type '(props: TextFieldProps) => Element' is missing the following properties from type 'HTMLDivElement': align, addEventListener, removeEventListener, accessKey, and 238 more. TS2322

有什么想法吗? 非常感谢

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

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

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

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

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

let intervariable = class MyClass{}
export const MyClass = intervariable; // TypeScript does not export type here.
import {MyClass} from './myclass';

let abc: MyClass; // TypeScript error TS2749

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

import {MyClass} from './myclass';

let abc: InstanceType<typeof MyClass>; // no error
// the rest...

typeof 运算符为 class 值获取 class 构造函数类型,InstanceType 泛型获取所需的实例类型。

长话短说: 在你的情况下,你只需要写 InstanceType<typeof TextField> 而不是 TextField.

确保你在 .tsx 文件而不是 .ts 文件

.ts 文件更改为 .tsx

在我的情况下有效

对于未来的观众,错误也可能是由于您没有首先导入 class。

这应该是一个评论,但我没有足够的声誉。 我想分享一种使用 is to declare a type alias with the same name ( 推荐的解决方案的简洁方法。然后您可以像通常使用实例类型一样使用您的类型。

添加示例:

import {MyClass} from './myclass';

type MyClass = InstanceType<typeof MyClass>;

let abc: MyClass; // still no error!

编辑: 类型导入似乎也有效,而且看起来更干净:

import type {MyClass} from './myclass';

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

我不得不将 heroes: HEROES 更改为 heroes = HEROES

我 运行 在构建 Angular 应用程序时遇到同样的 x refers to a value, but is being used as a type here. Did you mean 'typeof x'? 错误。 我花了两个小时寻找修复程序,多次阅读 Stack Overflow post。我的简单错误。

要检查的另一件事是您正在执行的导入是否被 {} 包围。出现此消息的原因之一是因为任何未被 {} 包围的内容都被视为文件的默认导出。