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.
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:
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.
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
Comentários muito úteis
para mim a solução foi: