Typescript: O tipo de elemento JSX não tem nenhuma construção ou assinatura de chamada na v3.2.0-rc

Criado em 21 nov. 2018  Â·  27Comentários  Â·  Fonte: microsoft/TypeScript

Versão TypeScript: 3.2.0-rc, 3.2.1

Código

import * as React from "react";
import { Component, ReactType} from "react";
function App(props:{component:ReactType}) {
  const Comp: ReactType = props.component
  return (<Comp />)
}

Comportamento esperado:
A saída deve ser normal como TypeScript 3.1.6

Comportamento real:
TS2604: JSX element type 'Comp' does not have any construct or call signatures.

Bug JSTSX Duplicate

Comentários muito úteis

para mim a solução foi:

export type WrapperProps = {
    mainApp: React.ElementType
}

Todos 27 comentários

Está faltando o resto da mensagem de erro, mas, para ter certeza, certifique-se de que está usando a versão mais recente de @types/react e que não há duplicatas deixadas em seu node_modules ou arquivo de bloqueio.

EDIT: você provavelmente pretende usar ComponentType e não ReactType

@Kovensky

Certifiquei-me de usar o @types/react 16.7.7 mais recente e nenhuma duplicata @types/react em yarn.lock .
Se o problema for devido à duplicação de @types/react , ele retornará o erro Duplication of definition ... .

Eu volto para "typescript": "^3.1.6" então funciona normalmente.

Texto datilografado 3.2.1

outro exemplo


interface P1 {
  p?: boolean
  c?: string
}

interface P2 {
  p?: boolean
  c?: any // if you replace c with string, error goes away
  d?: any
}

declare var C: React.ComponentType<P1> | React.ComponentType<P2>


const a = <C p={true} /> // element does not have any ...

Parece que o problema está relacionado a novas alterações de "discriminantes anuláveis". Parece que ts não consegue encontrar uma interface comum para esses tipos.
Outro exemplo

interface P1 {
  p?: any
  c?: string // remove this and it's ok
}

interface P2 {
  p?: boolean
}

Temos um problema semelhante, exemplo rápido:

import * as React from 'react'

//
// Types
//

interface Config<P> {
  ElementType: React.ReactType<P>
}

interface EmptyProps {
}

interface Props {
  a?: string
}

type HProps = {
  configEmpty: Config<EmptyProps>,
  config: Config<Props>
}

//
// Component
//

const H: React.FC<HProps> = ({ config, configEmpty }) => {
  const A: React.ReactType<EmptyProps> = configEmpty.ElementType // assigned
  const B: React.ReactType<EmptyProps> = 'div' // assigned

  const C: React.ReactType<Props> = config.ElementType // assigned
  const D: React.ReactType<Props> = 'div' // in this case assignment failed

  return (
    <div>
      <A/> {/* TS2604: JSX element type 'A' does not have any construct or call signatures. */}
      <B/>

      <C/>
      <D/>
    </div>
  )
}

export default H

Eu vejo esse comportamento como completamente inválido, porque A e B têm os mesmos tipos . Ao mesmo tempo, B e D têm _tipos semelhantes_, mas D não é atribuível 🤔

Código no repo: https://github.com/layershifter/ts-issue

Eles não fazem isso, porque você está usando const . O tipo de A é typeof configEmpty.ElementType , mas o tipo de B é 'div' . Usar let s mostrará o mesmo comportamento em ambos.

@Kovensky e A e C ? Por que C funciona enquanto A falha com erro does not have any construct ?

Isso porque eu melhorei o tipo de ReactType para excluir componentes que não seriam capazes de receber os adereços que você está dando. Como nenhum dos elementos DOM pode receber { a: string | undefined } , eles são todos excluídos e apenas os componentes de função / classe ainda podem ser atribuídos a ele.

@Kovensky, obrigado 👍 Agora o problema com a atribuição está claro para mim, mas e isso?

import * as React from 'react'

//
// Types
//

interface Config<P> {
  ElementType: React.ReactType<P>
}

interface Empty {}
interface Props { a?: string }

type HProps = {
  configEmpty: Config<Empty>,
  config: Config<Props>
}

//
// Component
//

const H: React.FC<HProps> = ({ config, configEmpty }) => {
  const A: React.ReactType<Empty> = configEmpty.ElementType // is React.ReactType<Empty>
  const B: React.ReactType<Empty> = 'div' // is string
  const C: React.ReactType<Props> = config.ElementType // is React.ReactType<Props>

  return (
    <div>
      {/* React.ReactType<Empty> */} <A/> {/* <--- TS2604: JSX element type 'A' does not have any construct or call signatures. */}
      {/* React.ReactType<Empty> */} <B/>
      {/* React.ReactType<Props> */} <C/>
    </div>
  )
}

export default H

A e B têm os mesmos tipos obviamente definidos, por que A falha? É uma coisa realmente confusa.

Eu provavelmente diria que o erro de @rexpan e @goloveychuk é semelhante a # 28795 e # 28768 com base no construtor JSX condicional.

Hm, então o problema é que ReactType<any> retorna uma união de _cada tag jsx embutida_ (mais ComponentType<any> , mas essa parte não é problemática), e as assinaturas para esses componentes não simplificam trivialmente (há não uma assinatura que englobe perfeitamente todas as outras). Isso também depende do # 7294 para ser corrigido. No lado positivo, a alteração subjacente necessária para corrigir todos esses problemas JSX relatados é a mesma.

Para fins de contexto, fabricamos efetivamente um tipo como este:

declare const JsxSigs: {[K in keyof JSX.IntrinsicElements]: ((props: JSX.IntrinsicElements[K]) => JSX.Element)}[keyof JSX.IntrinsicElements];

que acaba sendo uma união de uma tonelada de assinaturas únicas.

Antes de mudar para uma união de todas as tags jsx embutidas, era _just_ string | ComponentType<any> , o que era ainda pior.

Sim, especialmente porque antes de 3.2, um string digite em uma tag apenas silenciosamente _disabled_ typechecker, porque o erro "índice não encontrado" que deveria ocorrer nunca ocorreu.

Este problema foi marcado como duplicado e não teve atividade no último dia. Ele foi fechado para fins de manutenção automática.

Encontrando um problema que pode estar relacionado. Eu tenho o seguinte componente:

function MaybeLabel(props: { useLabel: boolean }) {
   const { useLabel } = props;
   const TagName = useLabel ? 'label' : 'div';

   return <TagName>Woookie</TagName>
}

o que resulta em

error TS2604: JSX element type 'TagName' does não have any construct or call signatures.

enquanto

function MaybeLabel2(props: { useLabel: boolean }) {
   const { useLabel } = props;
   const TagName = useLabel ? 'span' : 'div';

   return <TagName>Woookie</TagName>
}

é completamente aceitável para o compilador de texto digitado. Como é:

export function MaybeLabel3(props: { useLabel: boolean }) {
    const { useLabel } = props;
    const TagName = useLabel ? 'label' : 'div';

    return React.createElement(TagName, 'Wookie')
}

Onde a única diferença em MaybeLabel2 é que estou usando span vez de label (usar span vez de div também parece aceitável ) MaybeLabel3 torna ainda mais estranho, já que deve ser exatamente o que MaybeLabel compilar.

Usando a versão mais recente de @ types / react e @ types / react-dom, e verificado o problema no texto datilografado 3.2.1, 3.2.2 e 3.3.0-dev.20181219. Em 3.1.6 tudo funciona como esperado (nenhum dos exemplos produz erros)

para mim a solução foi:

export type WrapperProps = {
    mainApp: React.ElementType
}

@ TacB0sS, por favor

Posso ter entendido mal o tópico, mas queria passar uma referência a um Elemento jsx para outro elemento jsx:

export const AppWrapper = hot(module)((props: WrapperProps) => {

    const MainApp = props.mainApp;
    if (!MainApp)  // <-- JSX elements MUST start with upper case!!
        throw new ImplementationMissingException("mainApp was not specified!!");

    return (
        <Router history={BrowserHistoryModule.getHistory()}>
            <MainApp prop1={"value"}/>
        </Router>)
});

Junto com:

export type WrapperProps = {
    mainApp: React.ElementType<{prop1:string}>
}

@ TacB0sS Para mim, o truque principal foi adicionar if condição. Parece que não importa se você usa React.ComponentType ou React.ElementType

Não tenho certeza se entendi o resultado disso. Tenho um erro semelhante que não consegui resolver. Aqui está meu caso de uso:

// Logo.tsx

import classNames from 'classnames';

interface Props extends React.HTMLAttributes<HTMLElement> {
  tag?: React.ReactType;
}

const Logo: React.SFC<Props> = props => {
  const { tag: Tag = 'div', className, ...rest } = props;
  return (
    <Tag
      className={classNames(styles.logo, className)}
      {...rest}
      dangerouslySetInnerHTML={{ __html: logo }}
    />
  );
};

e então estou usando-o assim em outro componente assim:

const Header: React.SFC<{}> = () => {
  return (
    <div>
      <Logo tag="h1" aria-label="Syn By Design: Eric Masiello's Portfolio" />
      Header online
    </div>
  );
};

Quando executo o compilador, recebo este erro:

components/Logo.tsx:13:6 - error TS2604: JSX element type 'Tag' does not have any construct or call signatures.

13     <Tag
        ~~~


Found 1 error.

Alguma ideia de como fazer isso funcionar?

Em vez de Component , use ComponentClass

Recebi este erro porque importei o padrão, mas declarei a exportação correspondente como nomeada em vez de padrão no arquivo .d.ts ... me confundiu por um tempo

Só queria adicionar isso aqui. Não tenho certeza se isso já foi dito, mas se você está fazendo um componente de pedido de aluguel, você deseja usar o tipo React.ComponentType

. " https://flow.org/en/docs/react/types/#toc -react-componenttype"

@ericmasiello Acabei usando React.ElementType para um componente passado dinamicamente. Meu caso de uso é basicamente o seguinte:

type Props = {
    heading: React.ElementType
}
const Header: FC<Props> = props => {
    const Header = props.heading ?? 'h2';
    return (
        <Header className="some-class"><children /></Header>
    )
}

@ericmasiello Acabei usando React.ElementType para um componente passado dinamicamente. Meu caso de uso é basicamente o seguinte:


type Props = {

    heading: React.ElementType

}

const Header: FC<Props> = props => {

    const Header = props.heading ?? 'h2';

    return (

        <Header className="some-class"><children /></Header>

    )

}

Legal! Qual versão do Typescript e qual versão de @ types / react você instalou?

@ericmasiello

Legal! Qual versão do Typescript e qual versão de @ types / react você instalou?

[email protected]
@ types / [email protected]

Resolvi esse problema fazendo qualquer uma destas duas coisas:

Caso 1:

Arquivo .d.ts:

declare module "foo" {
   interface PropFoo {
      propy: string;
   }

   class MyTypedComponent extends React.Component<PropFoo> { }
}

Reagir:

import MyTypedComponent from "foo";

function AnotherComponent() {

   /* Notice in here we have to use the dot operator and reference the component */
   return <MyTypedComponent.MyTypedComponent /> 
}

Observe que, para usar o componente recém-digitado, temos que escrever _MyTypedComponent.MyTypedComponent_. Isso pode ser óbvio para algumas pessoas, mas eu perdi muito tempo quando tudo que tive que fazer foi usar o operador ponto na importação e referenciar o componente.

Caso 2 [apenas outra maneira de escrever Caso 1]:

Arquivo .d.ts:

declare module "foo" {
   interface PropFoo {
      propy: string;
   }

   export default class MyTypedComponent extends React.Component<PropFoo> { } //Notice the export default in here
}

Reagir:

import MyTypedComponent from "foo";

function AnotherComponent() {

   /* Since this component is default exported, no need to use the dot operator */
   return <MyTypedComponent /> 
}

Então, basicamente, verifique suas exportações, exportações padrão e importações e certifique-se de estar referenciando corretamente.

Sinto muito pelo meu inglês e espero que isso ajude.

para mim a solução foi:

export type WrapperProps = {
  mainApp: React.ElementType
}

niu b

Esta página foi útil?
0 / 5 - 0 avaliações