Lỗi phần tử JSX loại 'lỗi' không có bất kỳ cấu trúc hoặc cuộc gọi chữ ký nào có nghĩa là gì?


157

Tôi đã viết một số mã:

function renderGreeting(Elem: React.Component<any, any>) {
    return <span>Hello, <Elem />!</span>;
}

Tôi đang gặp lỗi:

Kiểu phần tử JSX Elemkhông có bất kỳ chữ ký cấu trúc hoặc cuộc gọi nào

Nó có nghĩa là gì?

Câu trả lời:


196

Đây là một sự nhầm lẫn giữa các nhà xây dựng và các trường hợp .

Hãy nhớ rằng khi bạn viết một thành phần trong React:

class Greeter extends React.Component<any, any> {
    render() {
        return <div>Hello, {this.props.whoToGreet}</div>;
    }
}

Bạn sử dụng nó theo cách này:

return <Greeter whoToGreet='world' />;

Bạn không sử dụng nó theo cách này:

let Greet = new Greeter();
return <Greet whoToGreet='world' />;

Trong ví dụ đầu tiên, chúng ta đi xung quanh Greeter, hàm tạo cho thành phần của chúng ta. Đó là cách sử dụng đúng. Trong ví dụ thứ hai, chúng ta chuyển qua một thể hiện của Greeter. Điều đó không chính xác và sẽ thất bại khi chạy với lỗi như "Object không phải là hàm".


Vấn đề với mã này

function renderGreeting(Elem: React.Component<any, any>) {
    return <span>Hello, <Elem />!</span>;
}

là nó chờ đợi một ví dụ của React.Component. Những gì bạn muốn một hàm có một hàm tạo cho React.Component:

function renderGreeting(Elem: new() => React.Component<any, any>) {
    return <span>Hello, <Elem />!</span>;
}

hoặc tương tự:

function renderGreeting(Elem: typeof React.Component) {
    return <span>Hello, <Elem />!</span>;
}

31
Theo văn bản này, nếu bạn đang sử dụng @types/reactchúng thì dễ sử dụng nhấtfunction RenderGreeting(Elem: React.ComponentType) { ... }
Jthorpe 29/07/18

Chỉ tò mò, làm thế nào để chúng ta viết function renderGreeting(Elem: typeof React.Component)trong ES6?
Bruce Sun

Cảm ơn. Điều gì sẽ xảy ra nếu chúng ta muốn vượt qua một thành phần chức năng không trạng thái? Tôi đoán function renderGreeting (Elem: new() => React.SFC<any>){...}Nếu vậy tại sao chúng ta tuyên bố loại SFC như thế này: const Hello:React.SFC<any> = (props) => <div>Hello World</div>và không:const Hello: new() =>React.SFC<any> = (props) => <div>Hello World</div>
Ben Carp

1
@Jthorpe bình luận của bạn nên một câu trả lời và một câu trả lời được chấp nhận tại IMO đó.
Tomáš Hzigelbauer

export const BackNavigationTextWrapper = (WrappedComponent: typeof React.Component) => { const BackNavigationTextWrappedComponent = (props, { commonElements = {} }: any) => { return <WrappedComponent {...props} backLabel={commonElements.backLabel || 'Go back to reservation details'} /> }; BackNavigationTextWrappedComponent.type = WrappedComponent.type; return BackNavigationTextWrappedComponent; }; Tôi đang gặp lỗi "Thuộc tính 'loại' không tồn tại trên loại 'loại thành phần'".
Prakash P

60

Nếu bạn muốn lấy một lớp thành phần làm tham số (so với một thể hiện), hãy sử dụng React.ComponentClass:

function renderGreeting(Elem: React.ComponentClass<any>) {
    return <span>Hello, <Elem />!</span>;
}

Bây giờ với các thành phần chức năng trong hỗn hợp, có lẽ bạn nên sử dụng React.ComponentType<any>loại thay vì để bao gồm chúng.
Zack

34

Khi tôi chuyển đổi từ JSX sang TSX và chúng tôi giữ một số thư viện dưới dạng js / jsx và chuyển đổi các thư viện khác thành ts / tsx, tôi hầu như luôn quên thay đổi các câu lệnh nhập js / jsx trong các tệp TSX \ TS từ

import * as ComponentName from "ComponentName";

đến

import ComponentName from "ComponentName";

Nếu gọi một thành phần kiểu JSX (React.createClass) cũ từ TSX, thì hãy sử dụng

var ComponentName = require("ComponentName")


4
Tôi nghĩ bạn có ý nghĩa khác?
apieceofbart

5
Không cần thay đổi câu lệnh inport nếu bạn định cấu hình TypeScript (tức là in tsconfig.json) thành allowSyntheticDefaultImports. Xem: typescriptlang.org/docs/handbook/compiler-options.html và thảo luận ở đây: blog.jonasbandi.net/2016/10/...
jbandi

11

Nếu bạn thực sự không quan tâm đến đạo cụ thì loại rộng nhất có thể là React.ReactType.

Điều này sẽ cho phép chuyển các phần tử dom gốc dưới dạng chuỗi. React.ReactTypebao gồm tất cả những điều này:

renderGreeting('button');
renderGreeting(() => 'Hello, World!');
renderGreeting(class Foo extends React.Component {
   render() {
      return 'Hello, World!'
   }
});

8

Nếu bạn đang sử dụng vật liệu-ui , hãy chuyển đến định nghĩa kiểu của thành phần đang được TypeScript gạch chân. Nhiều khả năng bạn sẽ thấy một cái gì đó như thế này

export { default } from './ComponentName';

Bạn có 2 tùy chọn để khắc phục lỗi:

1.Thêm .defaultkhi sử dụng thành phần trong JSX:

import ComponentName from './ComponentName'

const Component = () => <ComponentName.default />

2. Đặt tên cho thành phần đang được xuất thành "mặc định" khi nhập:

import { default as ComponentName } from './ComponentName'

const Component = () => <ComponentName />

Bằng cách này, bạn không cần chỉ định .defaultmỗi khi bạn sử dụng thành phần.


1
Điều này đã giúp tôi trong việc khắc phục vấn đề của tôi.
WhiteWalker


2

Trong trường hợp của tôi, tôi đã sử dụng React.ReactNodenhư một loại cho một thành phần chức năng thay vì React.FCloại.

Trong thành phần này là chính xác:

export const PropertiesList: React.FC = (props: any) => {
  const list:string[] = [
    ' Consequat Phasellus sollicitudin.',
    ' Consequat Phasellus sollicitudin.',
    '...'
  ]

  return (
    <List
      header={<ListHeader heading="Properties List" />}
      dataSource={list}
        renderItem={(listItem, index) =>
          <List.Item key={index}> {listItem } </List.Item>
      }
    />
  )
}


2

Như @Jthorpe đã ám chỉ, ComponentClasschỉ cho phép Componenthoặc PureComponentkhông FunctionComponent.

Nếu bạn cố gắng vượt qua a FunctionComponent, bản thảo sẽ đưa ra một lỗi tương tự như ...

Type '(props: myProps) => Element' provides no match for the signature 'new (props: myProps, context?: any): Component<myProps, any, any>'.

Tuy nhiên, bằng cách sử dụng ComponentTypechứ không phải ComponentClassbạn cho phép cả hai trường hợp. Theo tệp khai báo phản ứng, loại được xác định là ...

type ComponentType<P = {}> = ComponentClass<P, any> | FunctionComponent<P>

2

Trong trường hợp của tôi, tôi đã bị mất newtrong định nghĩa loại.

some-js-component.d.ts tập tin:

import * as React from "react";

export default class SomeJSXComponent extends React.Component<any, any> {
    new (props: any, context?: any)
}

và bên trong tsxtệp nơi tôi đang cố gắng nhập thành phần chưa được gõ:

import SomeJSXComponent from 'some-js-component'

const NewComp = ({ asdf }: NewProps) => <SomeJSXComponent withProps={asdf} />

2

Khi khai báo thành phần React Class, sử dụng React.ComponentClass thay vì React.Componentsau đó nó sẽ sửa lỗi ts.


1

Bạn có thể dùng

function renderGreeting(props: {Elem: React.Component<any, any>}) {
    return <span>Hello, {props.Elem}!</span>;
}

Tuy nhiên, có làm việc sau đây?

function renderGreeting(Elem: React.ComponentType) {
    const propsToPass = {one: 1, two: 2};

    return <span>Hello, <Elem {...propsToPass} />!</span>;
}
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.