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.
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:
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.
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
Commentaire le plus utile
pour moi, la solution était: