Escribí un código:
function renderGreeting(Elem: React.Component<any, any>) {
return <span>Hello, <Elem />!</span>;
}
Recibo un error:
El tipo de elemento JSX
Elem
no tiene ninguna construcción o firma de llamada
Qué significa eso?
Escribí un código:
function renderGreeting(Elem: React.Component<any, any>) {
return <span>Hello, <Elem />!</span>;
}
Recibo un error:
El tipo de elemento JSX
Elem
no tiene ninguna construcción o firma de llamada
Qué significa eso?
Respuestas:
Esta es una confusión entre constructores e instancias .
Recuerde que cuando escribe un componente en React:
class Greeter extends React.Component<any, any> {
render() {
return <div>Hello, {this.props.whoToGreet}</div>;
}
}
Lo usas de esta manera:
return <Greeter whoToGreet='world' />;
No lo usas de esta manera:
let Greet = new Greeter();
return <Greet whoToGreet='world' />;
En el primer ejemplo, estamos pasando Greeter
, la función constructora de nuestro componente. Ese es el uso correcto. En el segundo ejemplo, estamos pasando una instancia de Greeter
. Eso es incorrecto y fallará en tiempo de ejecución con un error como "El objeto no es una función".
El problema con este código
function renderGreeting(Elem: React.Component<any, any>) {
return <span>Hello, <Elem />!</span>;
}
es que está esperando una instancia de React.Component
. Para qué quieres una función que tome un constructor para React.Component
:
function renderGreeting(Elem: new() => React.Component<any, any>) {
return <span>Hello, <Elem />!</span>;
}
o similarmente:
function renderGreeting(Elem: typeof React.Component) {
return <span>Hello, <Elem />!</span>;
}
function renderGreeting(Elem: typeof React.Component)
en ES6?
function renderGreeting (Elem: new() => React.SFC<any>){...}
si es así, ¿por qué declaramos el tipo de SFC como este: const Hello:React.SFC<any> = (props) => <div>Hello World</div>
y no:const Hello: new() =>React.SFC<any> = (props) => <div>Hello World</div>
export const BackNavigationTextWrapper = (WrappedComponent: typeof React.Component) => { const BackNavigationTextWrappedComponent = (props, { commonElements = {} }: any) => { return <WrappedComponent {...props} backLabel={commonElements.backLabel || 'Go back to reservation details'} /> }; BackNavigationTextWrappedComponent.type = WrappedComponent.type; return BackNavigationTextWrappedComponent; };
Recibo un error "La propiedad 'tipo' no existe en el tipo 'tipo de componente'".
Si desea tomar una clase de componente como parámetro (frente a una instancia), use React.ComponentClass
:
function renderGreeting(Elem: React.ComponentClass<any>) {
return <span>Hello, <Elem />!</span>;
}
React.ComponentType<any>
tipo en su lugar para incluirlos.
Cuando convierto de JSX a TSX y mantenemos algunas bibliotecas como js / jsx y convierto otras a ts / tsx, casi siempre olvido cambiar las declaraciones de importación js / jsx en los archivos TSX \ TS de
import * as ComponentName from "ComponentName";
a
import ComponentName from "ComponentName";
Si llama a un antiguo componente de estilo JSX (React.createClass) desde TSX, utilice
var ComponentName = require("ComponentName")
tsconfig.json
) allowSyntheticDefaultImports
. Ver: typescriptlang.org/docs/handbook/compiler-options.html y discusión aquí: blog.jonasbandi.net/2016/10/…
Si realmente no te interesan los accesorios, entonces el tipo más amplio posible es React.ReactType
.
Esto permitiría pasar elementos dom nativos como una cadena. React.ReactType
cubre todo esto:
renderGreeting('button');
renderGreeting(() => 'Hello, World!');
renderGreeting(class Foo extends React.Component {
render() {
return 'Hello, World!'
}
});
Si está utilizando material-ui , vaya a la definición de tipo del componente, que TypeScript subraya. Lo más probable es que veas algo como esto
export { default } from './ComponentName';
Tiene 2 opciones para resolver el error:
1.Agregue .default
cuando use el componente en JSX:
import ComponentName from './ComponentName'
const Component = () => <ComponentName.default />
2. Cambie el nombre del componente, que se está exportando como "predeterminado", al importar:
import { default as ComponentName } from './ComponentName'
const Component = () => <ComponentName />
De esta manera, no necesita especificar .default
cada vez que usa el componente.
Lo siguiente funcionó para mí: https://github.com/microsoft/TypeScript/issues/28631#issuecomment-472606019 Lo soluciono haciendo algo como esto:
const Component = (isFoo ? FooComponent : BarComponent) as React.ElementType
En mi caso, estaba usando React.ReactNode
como tipo para un componente funcional en lugar de React.FC
tipo.
En este componente para ser exactos:
export const PropertiesList: React.FC = (props: any) => {
const list:string[] = [
' Consequat Phasellus sollicitudin.',
' Consequat Phasellus sollicitudin.',
'...'
]
return (
<List
header={<ListHeader heading="Properties List" />}
dataSource={list}
renderItem={(listItem, index) =>
<List.Item key={index}> {listItem } </List.Item>
}
/>
)
}
Como aludió @Jthorpe, ComponentClass
solo permite cualquiera Component
o PureComponent
no pero a FunctionComponent
.
Si intenta pasar un FunctionComponent
, mecanografiado arrojará un error similar a ...
Type '(props: myProps) => Element' provides no match for the signature 'new (props: myProps, context?: any): Component<myProps, any, any>'.
Sin embargo, al utilizar en ComponentType
lugar de ComponentClass
permitir ambos casos. Según el archivo de declaración de reacción, el tipo se define como ...
type ComponentType<P = {}> = ComponentClass<P, any> | FunctionComponent<P>
En mi caso me faltaba new
la definición de tipo.
some-js-component.d.ts
expediente:
import * as React from "react";
export default class SomeJSXComponent extends React.Component<any, any> {
new (props: any, context?: any)
}
y dentro del tsx
archivo donde estaba tratando de importar el componente sin tipo:
import SomeJSXComponent from 'some-js-component'
const NewComp = ({ asdf }: NewProps) => <SomeJSXComponent withProps={asdf} />
Al declarar el componente React Class, use en React.ComponentClass
lugar de React.Component
entonces solucionará el error ts.
Puedes usar
function renderGreeting(props: {Elem: React.Component<any, any>}) {
return <span>Hello, {props.Elem}!</span>;
}
Sin embargo, ¿funciona lo siguiente?
function renderGreeting(Elem: React.ComponentType) {
const propsToPass = {one: 1, two: 2};
return <span>Hello, <Elem {...propsToPass} />!</span>;
}
@types/react
, es más fácil de usarfunction RenderGreeting(Elem: React.ComponentType) { ... }