Typescript: Le type d'élément JSX n'a ​​pas de construction ou de signature d'appel dans la v3.2.0-rc

Créé le 21 nov. 2018  ·  27Commentaires  ·  Source: microsoft/TypeScript

Version TypeScript: 3.2.0-rc, 3.2.1

Code

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

Comportement prévisible:
Doit sortir normal comme TypeScript 3.1.6

Comportement réel:
TS2604: JSX element type 'Comp' does not have any construct or call signatures.

Bug JSTSX Duplicate

Commentaire le plus utile

pour moi, la solution était:

export type WrapperProps = {
    mainApp: React.ElementType
}

Tous les 27 commentaires

Il manque le reste du message d'erreur mais, pour être sûr, assurez-vous que vous utilisez la dernière version de @types/react et qu'il ne reste plus de doublons dans votre node_modules ou votre fichier de verrouillage.

EDIT: vous voulez probablement utiliser ComponentType et non ReactType

@Kovensky

Je me suis assuré d'utiliser le dernier @types/react 16.7.7 et aucun doublon @types/react dans yarn.lock .
Si le problème est dû à la duplication de @types/react , il renverra l'erreur Duplication of definition ... .

Je reviens à "typescript": "^3.1.6" puis cela fonctionne normalement.

Typographie 3.2.1

autre exemple


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 ...

Il semble que le problème soit lié à de nouveaux changements de "discriminants pouvant être annulés". On dirait que ts ne peut pas trouver d'interface commune pour ces types.
Autre exemple

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

interface P2 {
  p?: boolean
}

Nous avons un problème similaire, exemple rapide:

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

Je vois ce comportement comme complètement invalide, car A et B ont les mêmes types . Dans le même temps, B et D ont des _ types similaires_, mais D n'est pas assignable 🤔

Code dans le repo: https://github.com/layershifter/ts-issue

Ils ne le font pas, car vous utilisez const . Le type de A est typeof configEmpty.ElementType , mais le type de B est 'div' . L'utilisation de let s affichera le même comportement sur les deux.

@Kovensky qu'en est-il de A et C ? Pourquoi C fonctionne alors que A échoue avec does not have any construct erreur

C'est parce que j'ai amélioré le type de ReactType pour exclure les composants qui ne pourraient pas recevoir les accessoires que vous lui donnez. Etant donné qu'aucun des éléments DOM ne peut recevoir { a: string | undefined } , ils sont tous exclus et seuls les composants de fonction / classe sont encore autorisés à lui être affectés.

@Kovensky merci 👍 Maintenant, le problème de l'affectation est clair pour moi, mais qu'en est-il?

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 et B a les mêmes types évidemment définis, pourquoi A échoue? C'est vraiment déroutant.

Je dirais probablement que l' erreur de @rexpan et @goloveychuk est similaire à # 28795 et # 28768 basé sur le constructeur JSX conditionnel.

Hm, donc le problème est que ReactType<any> renvoie une union de _ chaque tag jsx intégré_ (plus ComponentType<any> , mais cette partie n'est pas problématique), et les signatures de ces composants ne se simplifient pas trivialement (il y a pas une signature qui englobe parfaitement toutes les autres). Cela aussi dépend du # 7294 pour être corrigé. Du côté positif, le changement sous-jacent nécessaire pour résoudre tous ces problèmes JSX qui sont signalés est le même.

Pour le contexte, nous fabriquons effectivement un type comme celui-ci:

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

qui finit par être une union d'une tonne de signatures uniques.

Avant de le changer pour qu'il soit une union de toutes les balises jsx intégrées, c'était _just_ string | ComponentType<any> , ce qui était encore pire.

Oui, surtout depuis la version 3.2, un type string dans une balise juste tranquillement _disabled_ typechecker, parce que l'erreur "index not found" qu'il était censé émettre ne s'est jamais produite.

Ce problème a été marqué comme doublon et n'a enregistré aucune activité au cours de la dernière journée. Il a été fermé à des fins d'entretien ménager automatique.

Rencontrer un problème qui pourrait être lié. J'ai le composant suivant:

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

   return <TagName>Woookie</TagName>
}

ce qui se traduit par

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

tandis que

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

   return <TagName>Woookie</TagName>
}

est tout à fait acceptable pour le compilateur dactylographié. Comme si:

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

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

Là où la seule différence dans MaybeLabel2 est que j'utilise span au lieu de label (utiliser span au lieu de div semble également acceptable ). MaybeLabel3 rend encore plus étrange, car cela devrait être exactement ce sur quoi MaybeLabel compile.

Utilisation de la dernière version de @ types / react et @ types / react-dom, et vérification du problème dans typescript 3.2.1, 3.2.2 et 3.3.0-dev.20181219. En 3.1.6, tout fonctionne comme prévu (aucun des exemples ne produit d'erreurs)

pour moi, la solution était:

export type WrapperProps = {
    mainApp: React.ElementType
}

@ TacB0sS veuillez préciser.

J'ai peut-être mal compris le fil, mais je voulais passer une référence à un élément jsx à un autre élément 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>)
});

Ensemble avec:

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

@ TacB0sS Pour moi, l'astuce principale était d'ajouter la condition if . Il semble que peu importe que vous utilisiez React.ComponentType ou React.ElementType

Je ne suis pas sûr de comprendre le résultat. J'ai une erreur similaire que je n'ai pas pu résoudre. Voici mon cas d'utilisation:

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

et puis je l'utilise comme tel dans un autre composant comme ceci:

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

Lorsque j'exécute le compilateur, j'obtiens cette erreur:

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

13     <Tag
        ~~~


Found 1 error.

Des idées pour faire fonctionner cela?

Au lieu de Component , utilisez ComponentClass

J'ai eu cette erreur parce que j'ai importé la valeur par défaut mais déclaré l'exportation correspondante comme nommée au lieu de par défaut dans le fichier .d.ts ... m'a confondu pendant un moment

Je voulais juste ajouter ceci ici. Je ne sais pas si cela a déjà été dit, mais si vous effectuez un composant de commande de locataire, vous souhaitez utiliser le type React.ComponentType

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

@ericmasiello J'ai fini par utiliser React.ElementType pour un composant passé dynamiquement. Mon cas d'utilisation est essentiellement le suivant:

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

@ericmasiello J'ai fini par utiliser React.ElementType pour un composant passé dynamiquement. Mon cas d'utilisation est essentiellement le suivant:


type Props = {

    heading: React.ElementType

}

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

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

    return (

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

    )

}

Cool! Quelle version de Typescript et quelle version de @ types / react avez-vous installée?

@ericmasiello

Cool! Quelle version de Typescript et quelle version de @ types / react avez-vous installée?

[email protected]
@ types / [email protected]

J'ai résolu ce problème en faisant l'une de ces deux choses:

Cas 1:

Fichier .d.ts:

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

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

Réagir:

import MyTypedComponent from "foo";

function AnotherComponent() {

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

Notez que, pour utiliser le composant nouvellement typé, nous devons écrire _MyTypedComponent.MyTypedComponent_. Cela peut être évident pour certaines personnes, mais j'ai perdu beaucoup de temps alors que tout ce que j'avais à faire était d'utiliser l'opérateur point sur l'importation et de référencer le composant.

Cas 2 [juste une autre façon d'écrire Cas 1]:

Fichier .d.ts:

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

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

Réagir:

import MyTypedComponent from "foo";

function AnotherComponent() {

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

Donc, en gros, vérifiez vos exportations, vos exportations par défaut et vos importations et assurez-vous que vous faites correctement référence.

Je suis vraiment désolé pour mon anglais et j'espère que cela aide.

pour moi, la solution était:

export type WrapperProps = {
  mainApp: React.ElementType
}

niu b

Cette page vous a été utile?
0 / 5 - 0 notes