TypeScript-Version: 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 />)
}
Erwartetes Verhalten:
Sollte normal als TypeScript 3.1.6 ausgegeben werden
Tatsächliches Verhalten:
TS2604: JSX element type 'Comp' does not have any construct or call signatures.
Hier fehlt der Rest der Fehlermeldung. Stellen Sie jedoch sicher, dass Sie sich auf der neuesten Version von @types/react
und dass in Ihren node_modules oder in der Sperrdatei keine Duplikate mehr vorhanden sind.
BEARBEITEN: Sie möchten wahrscheinlich ComponentType und nicht ReactType verwenden
@ Kovensky
Ich habe sichergestellt, dass die neuesten @types/react 16.7.7
und keine Duplikate @types/react
in yarn.lock
.
Wenn das Problem auf die Duplizierung von @types/react
, wird der Fehler Duplication of definition ...
.
Ich kehre zu "typescript": "^3.1.6"
dann funktioniert es normal.
Typoskript 3.2.1
anderes Beispiel
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 ...
Es sieht so aus, als ob das Problem mit neuen Änderungen an "nullbaren Diskriminanten" zusammenhängt. Es sieht so aus, als ob ts keine gemeinsame Schnittstelle für diese Typen finden kann.
Anderes Beispiel
interface P1 {
p?: any
c?: string // remove this and it's ok
}
interface P2 {
p?: boolean
}
Wir haben ein ähnliches Problem, schnelles Beispiel:
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
Ich sehe dieses Verhalten als völlig ungültig an, da A
und B
die gleichen Typen haben . Gleichzeitig haben B
und D
ähnliche Typen_, aber D
ist nicht zuweisbar 🤔
Code im Repo: https://github.com/layershifter/ts-issue
Sie tun es nicht, weil Sie const
. Die Art von A
ist typeof configEmpty.ElementType
, aber die Art von B
ist 'div'
. Die Verwendung von let
s zeigt auf beiden das gleiche Verhalten.
@Kovensky was ist mit A
und C
? Warum funktioniert C
während A
mit einem Fehler von does not have any construct
fehlschlägt?
Das liegt daran, dass ich den Typ von ReactType
verbessert habe, um Komponenten auszuschließen, die die Requisiten, die Sie ihm geben, nicht empfangen können. Da keines der DOM-Elemente { a: string | undefined }
empfangen kann, werden sie alle ausgeschlossen, und es dürfen nur noch Funktions- / Klassenkomponenten zugewiesen werden.
@ Kovensky danke 👍 Jetzt ist das Problem mit der Zuordnung für mich klar, aber was ist damit?
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
und B
haben dieselben offensichtlich definierten Typen. Warum schlägt A
fehl? Es ist wirklich verwirrend.
Ich würde wahrscheinlich sagen, dass der Fehler von @goloveychuk ähnlich dem von # 28795 und # 28768 ist, basierend auf dem bedingten JSX-Konstruktor.
Hm, das Problem ist also, dass ReactType<any>
eine Vereinigung von _jedem eingebauten jsx-Tag_ (plus ComponentType<any>
, aber dieser Teil ist nicht problematisch) zurückgibt und die Signaturen für diese Komponenten nicht trivial vereinfachen (gibt es keine Unterschrift, die alle anderen perfekt umfasst). Auch dies hängt davon ab, dass # 7294 behoben werden muss. Auf der positiven Seite ist die zugrunde liegende Änderung, die zur Behebung all dieser gemeldeten JSX-Probleme erforderlich ist, dieselbe.
Für den Kontext stellen wir effektiv einen Typ wie diesen her:
declare const JsxSigs: {[K in keyof JSX.IntrinsicElements]: ((props: JSX.IntrinsicElements[K]) => JSX.Element)}[keyof JSX.IntrinsicElements];
was letztendlich zu einer Vereinigung einer Tonne einzigartiger Signaturen führt.
Bevor ich es geändert habe, um eine Vereinigung aller eingebauten jsx-Tags zu sein, war es _just_ string | ComponentType<any>
, was noch schlimmer war.
Ja, zumal vor 3.2 ein string
-Typ in einem Tag nur leise _disabled_ typechecker eingab, weil der Fehler "Index nicht gefunden", den er ausgeben sollte, nie aufgetreten ist.
Dieses Problem wurde als Duplikat markiert und hat am letzten Tag keine Aktivität gesehen. Es wurde aus Gründen der automatischen Haushaltsführung geschlossen.
Auf ein Problem stoßen, das möglicherweise damit zusammenhängt. Ich habe die folgende Komponente:
function MaybeLabel(props: { useLabel: boolean }) {
const { useLabel } = props;
const TagName = useLabel ? 'label' : 'div';
return <TagName>Woookie</TagName>
}
was in ... endet
error TS2604: JSX element type 'TagName' does
nicht have any construct or call signatures.
während
function MaybeLabel2(props: { useLabel: boolean }) {
const { useLabel } = props;
const TagName = useLabel ? 'span' : 'div';
return <TagName>Woookie</TagName>
}
ist für den Typoskript-Compiler völlig akzeptabel. Wie es ist:
export function MaybeLabel3(props: { useLabel: boolean }) {
const { useLabel } = props;
const TagName = useLabel ? 'label' : 'div';
return React.createElement(TagName, 'Wookie')
}
Der einzige Unterschied bei MaybeLabel2
besteht darin, dass ich span
anstelle von label
(die Verwendung von span
anstelle von div
scheint ebenfalls akzeptabel zu sein ). MaybeLabel3
macht es noch seltsamer, da dies genau das sein sollte, was MaybeLabel
kompiliert.
Verwenden Sie die neueste Version von @ types / react und @ types / react-dom und überprüfen Sie das Problem in Typoskript 3.2.1, 3.2.2 und 3.3.0-dev.20181219. In 3.1.6 funktioniert alles wie erwartet (keines der Beispiele führt zu Fehlern)
Für mich war die Lösung:
export type WrapperProps = {
mainApp: React.ElementType
}
@ TacB0sS bitte
Ich habe den Thread möglicherweise falsch verstanden, wollte aber einen Verweis auf ein jsx-Element an ein anderes jsx-Element übergeben:
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>)
});
Zusammen mit:
export type WrapperProps = {
mainApp: React.ElementType<{prop1:string}>
}
@ TacB0sS Für mich war der Haupttrick das Hinzufügen der Bedingung if
. Sieht so aus, als wäre es egal, ob Sie React.ComponentType
oder React.ElementType
Ich bin mir nicht sicher, ob ich das Ergebnis verstehe. Ich habe einen ähnlichen Fehler, den ich nicht beheben konnte. Hier ist mein Anwendungsfall:
// 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 }}
/>
);
};
und dann benutze ich es so in einer anderen Komponente wie folgt:
const Header: React.SFC<{}> = () => {
return (
<div>
<Logo tag="h1" aria-label="Syn By Design: Eric Masiello's Portfolio" />
Header online
</div>
);
};
Wenn ich den Compiler starte, erhalte ich folgende Fehlermeldung:
components/Logo.tsx:13:6 - error TS2604: JSX element type 'Tag' does not have any construct or call signatures.
13 <Tag
~~~
Found 1 error.
Irgendwelche Ideen, wie das funktioniert?
Verwenden Sie anstelle von Component
ComponentClass
Ich habe diesen Fehler erhalten, weil ich Standard importiert habe, aber den entsprechenden Export in der Datei .d.ts
als benannt anstelle von Standard deklariert habe ... hat mich eine Weile verwirrt
Ich wollte das nur hier hinzufügen. Sie sind sich nicht sicher, ob dies bereits gesagt wurde, aber wenn Sie eine Mietauftragskomponente ausführen, möchten Sie den Typ React.ComponentType verwenden
. " https://flow.org/en/docs/react/types/#toc -react-componenttype"
@ericmasiello Am Ende React.ElementType
für eine dynamisch übergebene Komponente verwendet. Mein Anwendungsfall ist im Grunde der folgende:
type Props = {
heading: React.ElementType
}
const Header: FC<Props> = props => {
const Header = props.heading ?? 'h2';
return (
<Header className="some-class"><children /></Header>
)
}
@ericmasiello Am Ende
React.ElementType
für eine dynamisch übergebene Komponente verwendet. Mein Anwendungsfall ist im Grunde der folgende:type Props = { heading: React.ElementType } const Header: FC<Props> = props => { const Header = props.heading ?? 'h2'; return ( <Header className="some-class"><children /></Header> ) }
Cool! Welche Version von Typescript und welche Version von @ types / react haben Sie installiert?
@ericmasiello
Cool! Welche Version von Typescript und welche Version von @ types / react haben Sie installiert?
[email protected]
@ types / [email protected]
Ich habe dieses Problem gelöst, indem ich eines dieser beiden Dinge getan habe:
.d.ts Datei:
declare module "foo" {
interface PropFoo {
propy: string;
}
class MyTypedComponent extends React.Component<PropFoo> { }
}
Reagieren:
import MyTypedComponent from "foo";
function AnotherComponent() {
/* Notice in here we have to use the dot operator and reference the component */
return <MyTypedComponent.MyTypedComponent />
}
Beachten Sie, dass wir _MyTypedComponent.MyTypedComponent_ schreiben müssen, um die neu typisierte Komponente zu verwenden. Dies mag für einige Leute offensichtlich sein, aber ich habe viel Zeit verschwendet, als ich beim Importieren und Verweisen auf die Komponente nur den Punktoperator verwenden musste.
.d.ts Datei:
declare module "foo" {
interface PropFoo {
propy: string;
}
export default class MyTypedComponent extends React.Component<PropFoo> { } //Notice the export default in here
}
Reagieren:
import MyTypedComponent from "foo";
function AnotherComponent() {
/* Since this component is default exported, no need to use the dot operator */
return <MyTypedComponent />
}
Überprüfen Sie also im Grunde Ihre Exporte, Standardexporte und Importe und stellen Sie sicher, dass Sie richtig referenzieren.
Mein Englisch tut mir sehr leid und ich hoffe, das hilft.
Für mich war die Lösung:
export type WrapperProps = { mainApp: React.ElementType }
niu b
Hilfreichster Kommentar
Für mich war die Lösung: