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

Posted

技术标签:

【中文标题】ReactJS 和 Typescript :引用一个值,但在此处用作类型 (TS2749)【英文标题】:ReactJS and Typescript : refers to a value, but is being used as a type here (TS2749) 【发布时间】:2020-09-15 10:56:29 【问题描述】:

我正在使用 Typescript 和 Material-ui 在 .tsx 文件中编写一个 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;
  

在编译期间,我的引用声明出现错误:

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

我试图在我的声明中添加“typeof TextField”,但在我的渲染中评估 ref 属性时,我收到了另一条消息:

Type 'RefObject Element>' 不可赋值 输入 '((实例:htmlDivElement | null) => void) | 参考对象 |空 |不明确的'。类型 'RefObject Element>' 不可分配给 键入“参考对象”。 类型 '(props: TextFieldProps) => Element' 缺少来自类型 'HTMLDivElement' 的以下属性:align、addEventListener、 removeEventListener、accessKey 等 238 个。 TS2322

有什么想法吗? 非常感谢

【问题讨论】:

可能与***.com/questions/46703364/…相关 我遇到了同样的问题,这很有效! ***.com/a/65332778/11025497 【参考方案1】:

这应该是评论,但我没有足够的声誉。 我想分享一个使用the accepted answer 推荐的解决方案的干净方法是声明一个具有相同名称的类型别名(it does not cause a conflict)。然后,您可以像通常使用实例类型一样使用您的类型。

添加到示例中:

import MyClass from './myclass';

type MyClass = InstanceType<typeof MyClass>;

let abc: MyClass; // still no error!

编辑:类型导入似乎也能正常工作,而且看起来更简洁:

import type MyClass from './myclass';

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

【讨论】:

【参考方案2】:

.ts 文件更改为.tsx

在我的情况下它有效

【讨论】:

这应该放在顶部。拯救了我的一天。 太棒了!在一行中节省了我的一天【参考方案3】:

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

【讨论】:

这是人们应该检查的第一件事。 有一个类似的问题同样的答案***.com/questions/58341545/…【参考方案4】:

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

【讨论】:

【参考方案5】:

我不得不将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 帖子。我犯了一个简单的错误。

【讨论】:

【参考方案6】:

对于未来的查看者,错误也可能是由于您没有首先导入该类。

【讨论】:

【参考方案7】:

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

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

然而,真正的问题是当您从模块中导出类时动态。当你以某种方式导出类时,TypeScript 只能导出类的 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 运算符为您提供类值的类构造函数类型,而 InstanceType 泛型为您提供所需的实例类型。

TL;DR: 在你的情况下,你只需要写 InstanceType&lt;typeof TextField&gt; 而不是 TextField

【讨论】:

我花了太多时间研究这个...谢谢。另一个见解是,Jest 管道与生产/开发管道完全不同...... 是的,由于某种原因,TS 文档中没有正确解释这一点。我的团队在使用一些非 TS 库处理 TS-React 项目时多次遇到此问题。我花了一段时间才弄清楚这一点。

以上是关于ReactJS 和 Typescript :引用一个值,但在此处用作类型 (TS2749)的主要内容,如果未能解决你的问题,请参考以下文章

TypeError:fs.​​existsSync 不是函数(Electron/ReactJS/Typescript)

typesafe 使用 reactjs 和 typescript 选择 onChange 事件

ReactJs 和 Typescript,使用 TSX 时如何更改对象内变量的状态

当 ReactJS 遇到 TypeScript

在 ReactJS + Typescript 中加载 CSS 模块并重新连接反应

typescript+reactjs+requirejs:如何将 react-dom 导入 typescript