67 votes

Type de composant générique sans état? OU Extension de l'interface de fonction générique en tapuscrit pour avoir un autre générique?

Problème: l'interface de L' Stateless Functional Component est donné comme

interface SFC<P = {}> {
    (props: P & { children?: ReactNode }, context?: any): ReactElement<any> | null;
    propTypes?: ValidationMap<P>;
}

L'hélice type de mon composant est aussi générique que:

interface Prop<V>{
    num: V;
}

Comment bien définir mes composants? comme:

const myCom: <T>SFC<Prop<T>> = <T>(props: Prop<T>)=> <div>test</div>

donne une erreur lors de l' character 27 que Cannot find name 'T'

Ici est :Tapuscrit de l'aire de Jeux du modifiés exemple

MyFindings:

1:Tapuscrit 2.9.1 soutien Dynamique Composant Générique: http://www.typescriptlang.org/docs/handbook/release-notes/typescript-2-9.html#generic-type-arguments-in-jsx-elements

class myCom<T> extends React.Component<Prop<T>, any> {
   render() {
      return <div>test</div>;
   }
}

2: Extension de l' SFC de faire une nouvelle interface comme mentionné dans la réponse suivante serait de faire du composant prop type any: Tapuscrit Réagir apatrides de la fonction avec le paramètre générique/types de retour que je ne veux pas. Je veux donner le bon type pour mon prop

55voto

jmattheis Points 5406

Vous ne pouvez pas utiliser des génériques comme ceci:

const myCom: <T>SFC<Prop<T>> = <T>(props: Prop<T>)=> <div>test</div>

Le Tapuscrit spec états:

Une construction de la forme

< T > ( ... ) => { ... }

pourrait être analysée comme une flèche expression de fonction avec un paramètre de type ou d'un type d'assertion appliquée à une flèche fonction sans paramètre de type.

source: Microsoft/fichier d'enregistrement spec.md

Votre déclaration ne correspondent pas au modèle défini dans le fichier d'enregistrement spec, donc il l'habitude de travailler.

Vous pouvez toutefois de ne pas utiliser le SFC de l'interface et de simplement déclarer vous-même.

interface Prop<V> {
    num: V;
}

// normal function
function Abc<T extends string | number>(props: Prop<T>): React.ReactElement<Prop<T>> {
    return <div />;
}

// const lambda function
const Abc: <T extends string | number>(p: Prop<T>) => React.ReactElement<Prop<T>> = (props) => {
   return <div />
};

export default function App() {
    return (
        <React.Fragment>
            <Abc<number> num={1} />
            <Abc<string> num="abc" />
            <Abc<string> num={1} /> // string expected but was number
        </React.Fragment>
    );
}

28voto

vadistic Points 161

Il existe un modèle pour atténuer ce problème en déclarant un alias de type de composant générique en dehors du composant, puis en l'affirmant simplement lorsque vous en avez besoin.

Pas aussi joli, mais toujours réutilisable et strict.

 interface IMyComponentProps<T> {
  name: string
  type: T
}

// instead of inline with component assignment
type MyComponentI<T = any> = React.FC<IMyComponentProps<T>>

const MyComponent: MyComponentI = props => <p {...props}>Hello</p>

const TypedComponent = MyComponent as MyComponentI<number>
 

16voto

Chris Points 883

Modèle d'usine:

 import React, { SFC } from 'react';

export interface GridProps<T = unknown> {
  data: T[];
  renderItem: (props: { item: T }) => React.ReactChild;
}

export const GridFactory = <T extends any>(): SFC<GridProps<T>> => () => {
  return (
    <div>
      ...
    </div>
  );
};

const Grid = GridFactory<string>();
 

9voto

Jose A Points 978

Je propose une solution similaire mais légèrement différente (brainstorming avec un ami). Nous essayions de créer un wrapper Formik et avons réussi à le faire fonctionner de la manière suivante:

 import React, { memo } from 'react';

export type FormDefaultProps<T> = {
  initialValues: T;
  onSubmit<T>(values: T, actions: FormikActions<T>): void;
  validationSchema?: object;
};

// We extract React.PropsWithChildren from React.FunctionComponent or React.FC
function component<T>(props: React.PropsWithChildren<FormDefaultProps<T>>) {
  // Do whatever you want with the props.
  return(<div>{props.children}</div>
}

// the casting here is key. You can use as typeof component to 
// create the typing automatically with the generic included..
export const FormDefault = memo(component) as typeof component;

 

Et puis, vous l'utilisez comme:

  <FormDefault<PlanningCreateValues>
        onSubmit={handleSubmit}
        initialValues={PlanningCreateDefaultValues}
      >
         {/*Or any other child content in here */}
        {pages[page]}
</FormDefault>
 

Je n'ai pas pu y parvenir avec des expressions de méthode:

const a: React.FC<MyProp> = (prop) => (<>MyComponent</>);

0voto

John Kennedy Points 2490

Tu as ceci:

 interface Prop<V> {
    num: V;
}
 

Et vous avez votre composant défini comme ceci:

 const myCom: SFC<Prop<T>> = <T>(props: Prop<T>)=> <div>test</div>
 

Cela ne fonctionnerait pas car vous auriez besoin de fournir un type concret pour le V dans l'interface puisque vous l'implémentez dans votre composant.

Cela ressemble à ceci:

 const myCom: SFC<Prop<object>> = <T>(props: Prop<T>)=> <div>test</div>
 

Notez mon utilisation de object là où vous aviez T . C'est juste un exemple.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X