Material-ui: Erreur de type de script dans le composant renvoyé par withStyles()

Créé le 28 sept. 2017  ·  55Commentaires  ·  Source: mui-org/material-ui

Lors de l'utilisation de withStyles() hoc dans le script dactylographié, j'obtiens l'erreur suivante lorsque j'essaie d'utiliser le composant renvoyé :

Type '{}' is not assignable to type 'IntrinsicAttributes & IntrinsicClassAttributes<App> & Readonly<{ children?: ReactNode; }> & Reado...'.
  Type '{}' is not assignable to type 'Readonly<WithStyles<"main">>'.
    Property 'classes' is missing in type '{}'.
  • [x] J'ai recherché les problèmes de ce référentiel et je pense qu'il ne s'agit pas d'un doublon.

Il semble que cette modification de la définition de type puisse être liée à ce problème.

Comportement prévisible

Étant donné le code du composant App ci-dessous, je devrais pouvoir utiliser le composant <App /> sans l'erreur de type comme je l'ai fait dans 1.0.0-beta.10.

Comportement actuel

Étant donné le code de composant App ci-dessous, essayer d'utiliser <App /> entraîne l'erreur susmentionnée.

Le code

import * as React from 'react';
import { withStyles } from 'material-ui/styles';

const styles = {
    main: {
        marginTop: 48,
        padding: 10,
    },
    foo: {
        margin: 0,
    },
};

interface Props {
    message: string;
};

type ClassNames = { classes: { [className in keyof typeof styles]: string } };

class App extends React.Component<Props & ClassNames> {
    render() {
        const { classes, message } = this.props;
        return (
            <div className={classes.main}>
                <div className={classes.foo} >
                    Hello World! {message}
                </div>
            </div>
        );
    }
}

export default withStyles(styles)(App);

Le contexte

Le code a bien fonctionné dans la version 1.0.0-beta.10, lorsque je suis passé à la version 1.0.0-beta.12, j'ai eu l'erreur de type.

Dans l'extrait de code fourni, j'ai utilisé l'astuce keyof typeof styles pour ne pas avoir besoin de définir deux fois une liste de noms de classe (je n'aime pas du tout la répétitivité). J'ai aussi essayé d'autres variantes :

type ClassNames = WithStyles<keyof typeof styles>;

et le faire de la manière la plus courante (comme on le voit dans styles.spec.tsx ):

type ComponentClassNames = 'main' | 'foo';
type ClassNames = WithStyles<ComponentClassNames>;

Je reçois toujours la même erreur.

Il semble que la définition de type précédente renverrait un composant dont le type d'accessoires serait StyledComponentProps qui a une propriété optionnelle classes . La nouvelle définition...

<P, C extends React.ComponentClass<P & StyledComponentProps<Names>>>(
    component: C
  ): C;

... renvoie le même type C que le composant, cela signifie que passer ClassNames qui n'est pas marqué comme facultatif se propage au composant renvoyé. Je vois mentionné ici l'utilisation de Partial<> que je pense que c'est un hack disgracieux.

Votre environnement

| Technologie | Versions |
|--------------|---------|
| Matériel-UI | 1.0.0-beta.12 |
| Réagir | 15.6.1 |
| navigateur | Chrome 61.0.3163.100 |

discussion typescript

Commentaire le plus utile

J'ai résolu en utilisant recompose

Exemple

import { StyleRules, Theme, withStyles } from "material-ui/styles";
import * as React from "react";
import { compose } from "recompose";

interface IProps {
    classes?: any; // <-- add question mark
    text: string;
}

const styles = (theme: Theme): StyleRules => ({
    root: {

    },
});

@compose(
    withStyles(styles),
)
export class MyComponent extends React.Component<IProps> {
    render() {
        const { classes, text } = this.props;
        return (
            <div className={classes.root}>
                {text}
            </div>
        );
    }
}

Tous les 55 commentaires

@cfilipov lors de la décoration d'une classe de composant, vous devez utiliser StyledComponentProps au lieu de WithStyles , et si en mode de vérification de type strict, vous devez utiliser l'opérateur d'assertion non nul ! pour extraire les champs de classes . C'est un compromis pour permettre l'utilisation de withStyles comme décorateur de classe. Les décorateurs de classe dans TypeScript souffrent de la limitation selon laquelle leur type de retour doit correspondre au type d'argument. Compte tenu de ces limitations, une seule option est possible :

  1. ne supporte pas l'utilisation de withStyles comme décorateur de classe
  2. exiger que vous passiez un accessoire factice classes lors de la construction d'un élément du type de composant décoré (le compromis précédent, qui était sans doute plus ennuyeux )
  3. exiger que classes soit considéré comme nullable à l'intérieur du composant, vous obligeant à utiliser l'opérateur ! lors de l'accès à ses champs ( le compromis actuel )

Je recommanderais fortement que si votre composant n'a pas d'état, vous utilisiez un composant fonctionnel sans état, qui nécessitera moins d'annotations de type et sera plus sûr pour le type :

export default withStyles(styles)<Props>(({ classes, message }) => (
  <div className={classes.main}>
    <div className={classes.foo}>
      Hello World! {message}
    </div>
  </div>
));

Je vois mentionné ici l'utilisation de Partial<> dont je pense que c'est un hack disgracieux.

Si vous lisez mon suivi de ce commentaire, vous verrez que Partial<> n'est pas requis.

Si vous lisez mon suivi de ce commentaire, vous verrez que Partial<> n'est pas requis.

J'ai vu votre commentaire concernant Partial<> . Utiliser StyledComponentProps revient essentiellement au même (c'est utiliser Partial<> dans cette définition). Mon reproche, c'est que les noms de classe doivent maintenant être accessibles avec ! (comme vous l'avez mentionné). Je pense que passer un accessoire factice classes ou exiger l'utilisation de ! sont tous deux de mauvais compromis.

Pour clarifier, je suppose que le problème fondamental que j'ai ici est le choix d'introduire une régression vers le hoc dans le but de contourner une limitation d'une fonctionnalité expérimentale de tapuscrit. J'admets un certain parti pris car je n'aime pas les décorateurs, alors que d'autres le font clairement, mais le compromis ici n'a pas de sens pour moi.

@cfilipov mon premier refactor des typages withStyles était de choisir l'option (1), c'est-à-dire que les typages étaient complètement corrects pour les composants de classe et de fonction, au détriment de l'utilisation de withStyles comme décorateur de classe . J'ai ensuite reçu des commentaires selon lesquels l'utilisation de la syntaxe du décorateur était une demande populaire, alors je suis passé à l'option (3). Je suis heureux de revoir cette décision; Moi aussi, je préférerais la sécurité des caractères au support des décorateurs dans leur état semi-fonctionnel actuel.

Ouais, je comprends le désir de soutenir une demande populaire comme celle-ci. Je veux aussi utiliser des décorateurs, mais je continue à rencontrer de nombreux problèmes avec eux à chaque fois que je le fais (en dehors de mui), alors j'ai personnellement décidé de ne pas les utiliser jusqu'à ce qu'ils soient prêts.

Il semble que vous partagez mon inquiétude et je n'ai pas grand-chose d'autre à ajouter, donc j'espère que d'autres personnes pourront fournir des commentaires dans cette direction pour aider à l'influencer.

Je suis passé de beta.13 à beta.10 pour voir si quelque chose avait changé et oui, c'est un vrai problème. Pour jeter mes 2 centimes ici, pour moi, les décorateurs sont expérimentaux. Ils pourraient évidemment être modifiés à l'avenir. Et jusque-là, je soutiendrais pleinement la manière précise à 100%. Je préférerais de loin avoir une sécurité de type cohérente au piratage de mes types pour que les choses fonctionnent.

8550 semble être une preuve supplémentaire que les gens sont confus par cela, et nous devrions envisager de ne pas prendre en charge @withStyles() tant que décorateur (en TypeScript).

Voici à quoi cela ressemblerait de « décorer » une classe si les saisies étaient correctes :

type NonStyleProps = {
  text: string
};

const styles = {
  root: {
    backgroundColor: 'red'
  }
};

const DecoratedComponent = withStyles(styles)(
  class extends React.Component<NonStyleProps & WithStyles<'root'>> {
    render() {
      return (
        <div className={this.props.classes.root}>
          {this.props.text}
        </div>
      );
    }
  }
);

@pelotom Je n'ai pas encore avancé de la version bêta.10 à cause de ce problème. J'ai déjà fait un commentaire sur le style d'une classe avec la méthode connect de Redux. Je pense que c'est relativement facile et robuste. dans #8059, le troisième commentaire est moi-même avec les types.

@pelotom Merci beaucoup de nous avoir withStyles de laisser tomber son support de décoration afin d'avoir une meilleure sécurité de type.

nous devrions envisager de ne pas prendre en charge @withStyles() en tant que décorateur (dans TypeScript).

@pelotom Je suis personnellement favorable à ce changement. @sebald Que veux-tu faire ici ?

C'est un simple changement; Je suis allé de l'avant et j'ai ouvert un PR au cas où vous voudriez y aller 🙂

@pelotom les frappes fonctionneraient-elles toujours si je les utilisais comme ça ?

interface IStyles {
    // styles interface
}
interface IHeaderInfoStyles {
    classes: any;
}
interface IHeaderInfoProps {
    // properties resulting from dispatches
}
interface IHeaderInfoInjectedProps {
   // props injected from parent if any
}
interface IHeaderInfoDispatchProps {
    // dispatches
}
interface IHeaderInfoState {
    // your state for the class
}

type HeaderInfoProps = IHeaderInfoProps & IHeaderInfoInjectedProps & IHeaderInfoDispatchProps & IHeaderInfoStyles;

class HeaderInfo extends Component<HeaderInfoProps, IHeaderInfoState> {

export const HeaderInfo_container = withStyles<IHeaderInfoInjectedProps, IStyles>(styles)(
    connect<IHeaderInfoProps, IHeaderInfoDispatchProps, (IHeaderInfoInjectedProps & IHeaderInfoStyles)>(mapStateToProps, mapDispatchToProps)(HeaderInfo),
);

@marcusjwhelan withStyles ne prend plus 2 paramètres de type, et vous ne devriez pas avoir à fournir un paramètre de type pour les styles (il peut être déduit de styles ). Vous devriez plutôt être capable d'écrire

withStyles(styles)<NonStyleProps>(...);

Si vous donnez les types pour mapStateToProps et mapDispatchToProps je pourrais peut-être vous montrer à quoi cela ressemblerait pour votre exemple.

tl;dr; Faisons les changements et voyons quel est le contrecoup, je suppose 👷🏻


@oliviertassinari @pelotom ¯_(ツ)_/¯ Je n'utilise pas de décorateurs, donc personnellement, je m'en fiche vraiment de ce changement, car je ne suis pas concerné. Mais il semble que beaucoup de gens se soucient de cette "fonctionnalité". C'est pourquoi nous l'avons ajouté en premier lieu. C'est à mon humble avis ce qui a la priorité ici.

Je suis très content des changements de withStyles , mais quand vous jetez un œil à d'autres bibliothèques plus fonctionnelles, comme ramda ou recompose , les frappes ne sont pas si strictes, ils ne sont pas non plus super sécurisés. Souvent, vous devez passer un générique, qui représente la valeur de retour d'une fonction. Pas joli mais cela fonctionnera pour 99,9% des utilisateurs.

Pourquoi ne pouvons-nous pas ramener les anciennes dactylographies qui fonctionnaient pour les personnes utilisant des décorateurs ? Parce qu'il avait deux génériques, nous pourrions peut-être avoir les deux typages côte à côte.

De plus, je suis un peu confus quant aux problèmes des gens avec les décorateurs (concernant "ne pas travailler"). Des bibliothèques comme Angular et https://nestjs.com/ en font un usage intensif après tout. Dans notre cas, les gens pourraient simplement ajouter WithStyles aux accessoires et tout va bien.

@sebald

Pourquoi ne pouvons-nous pas ramener les anciennes dactylographies qui fonctionnaient pour les personnes utilisant des décorateurs ? Parce qu'il avait deux génériques, nous pourrions peut-être avoir les deux typages côte à côte.

Je ne suis pas sûr de ce que vous voulez dire. Il n'y a jamais eu de dactylographie qui a permis aux gens d'utiliser des décorateurs sans douleur. La première implémentation souffrait de #8267, qui était que vous ne pouviez pas construire un élément d'un composant décoré sans passer un accessoire factice classes , par exemple <StyledComp classes={{} as any} /> . La deuxième implémentation (actuelle) souffre du problème inverse, à savoir que classes est considéré comme potentiellement undefined au sein de la classe de composants. Si vous souhaitez utiliser les décorateurs TypeScript dans leur forme actuelle, ce sont vos 2 seules options ; choisissez votre poison.

La troisième méthode consiste à utiliser le type correct, de sorte que classes soit défini dans la classe mais qu'il ne soit pas nécessaire de le transmettre en tant que prop. Pour avoir ces deux conditions, vous devez abandonner les décorateurs.

@pelotom Oui, désolé. Tu as raison. Ce n'est vraiment pas mon jour... 🤐 Alors fusionnons !

@sebald

De plus, je suis un peu confus quant aux problèmes des gens avec les décorateurs (concernant "ne pas travailler"). Des bibliothèques comme Angular et https://nestjs.com/ en font un usage intensif après tout.

Je ne sais pas comment ils sont utilisés dans Angular, mais il existe certainement des cas d'utilisation où les décorateurs peuvent être utilisés sans douleur; fondamentalement, si le décorateur n'a pas besoin de changer le type de classe qu'il décore, ils fonctionnent bien. Ce n'est pas la situation que nous avons ici; withStyles doit changer le type du composant qu'il décore.

@pelotom Oui, exactement. C'est juste la mutation qui est mauvaise. En fait, la façon dont TS implémente actuellement les décorateurs pourrait même être bonne pour les utilisateurs d'Angular, car les décorateurs AFAIK ont mis en place des contrats avec le framework, comme "enregistrer cette classe en tant que composant" ou "ajouter des métadonnées pour que je puisse l'utiliser dans le DI " ... dieu même écrire à ce sujet me fait sentir

@pelotom la raison pour laquelle j'ai les types comme je le fais est qu'ils fournissent la sécurité de type pour mes composants. Actuellement, les types n'ont pas de sécurité de type en ce qui concerne les composants. Les InjectedProps dans mon exemple sont les types requis par le composant pour fonctionner. Les types de connexion à partir de react-redux doivent être ceux de Props provenant de mapStateToProps et DispatchProps provenant de mapDispatchToProps .

À la toute fin, il doit y avoir les InjectProps pour que mon composant parent sache que je dois les injecter ou mon projet ne sera pas compilé. (C'est ce que je veux). Ce changement va-t-il migrer vers ce type de sécurité ?

@marcusjwhelan encore

@pelotom Question

@wcandillon Suivez-nous sur Twitter.

@pelotom J'ai

Éditer

Je l'ai compris.

J'interviens un peu tard dans cette discussion, mais j'ai vu une erreur similaire à celle mentionnée ici, et je n'ai pas encore déterminé comment je peux la corriger. J'utilise [email protected] et [email protected] .

const LoginForm = withStyles(styles)(
    class extends React.Component<WithStyles<'root' | 'button'>, ILoginFormState> {
    // ...
    }
);

render(
  <MuiThemeProvider theme={theme}>
    <LoginForm />
  </MuiThemeProvider>,
  document.getElementById('login-form')
);

Le message d'erreur que je reçois dans ce cas particulier est :

Type '{}' is not assignable to type 'IntrinsicAttributes & WithStyles<"root" | "button"> & StyledComponentP...'.
  Type '{}' is not assignable to type 'WithStyles<"root" | "button" | "progress" | "textField">'.
    Property 'classes' is missing in type '{}'.
 not assignable to type 'WithStyles<"root" | "button" | "progress" | "textField">'.
    Property 'classes' is missing in type '{}'.

lors de la décoration d'une classe de composant, vous devez utiliser StyledComponentProps au lieu de WithStyles

@pelotom - y a-t-il un exemple de cela quelque part ? J'ai beaucoup de mal à déterminer comment styliser une classe de composant avec état dans TypeScript.

@iamjem c'est un peu difficile à dire puisque vous n'avez pas fourni styles , mais il semble que le premier problème est que vous avez plus de clés de classe mentionnées dans styles que vous n'en mentionnez dans WithStyles<...> . Je pense que si vous le changez en

const LoginForm = withStyles(styles)(
    class extends React.Component<WithStyles<keyof typeof styles>, ILoginFormState> {
    // ...
    }
);

il devrait s'occuper du premier problème. Ensuite, il semble qu'il y ait un deuxième problème, à savoir que le type résultant de LoginForm est

React.ComponentType<WithStyles<"root" | "button"> & StyledComponentProps<"root" | "button">>

ce qui n'est évidemment pas correct ; il semble que l'absence d'accessoires non liés au style perturbe le système de types. Vous pouvez l'aider en étant explicite sur ce que sont les props sans style, en passant {} comme argument de type :

const LoginForm = withStyles(styles)<{}>( // <-- note the type argument
    class extends React.Component<WithStyles<keyof typeof styles>, ILoginFormState> {
    // ...
    }
);

Désolé, c'est si compliqué, j'aurais aimé connaître un moyen plus simple de faire fonctionner ce genre de choses !

Cela a fait l'affaire ! Merci pour l'aide rapide @pelotom. J'utilise React depuis longtemps, mais je viens juste de me lancer dans Material-ui et j'ai pensé essayer Typescript pendant que j'y suis. Inutile de dire que je trouve qu'il y a des cas extrêmes où il est difficile de dire comment rendre Typescript heureux.

J'ai résolu en utilisant recompose

Exemple

import { StyleRules, Theme, withStyles } from "material-ui/styles";
import * as React from "react";
import { compose } from "recompose";

interface IProps {
    classes?: any; // <-- add question mark
    text: string;
}

const styles = (theme: Theme): StyleRules => ({
    root: {

    },
});

@compose(
    withStyles(styles),
)
export class MyComponent extends React.Component<IProps> {
    render() {
        const { classes, text } = this.props;
        return (
            <div className={classes.root}>
                {text}
            </div>
        );
    }
}

Je me battais avec ce problème (et #8704), sans résultat clair au cours des derniers jours. Ensuite j'ai suivi les conseils de @pelotom :

vous devriez utiliser StyledComponentProps au lieu de WithStyles

et recherché sur GitHub des moyens similaires pour résoudre ce problème. Et j'ai trouvé UN exemple de travail . C'est un bon, cependant, et cela a résolu mon problème - conteneur et composant séparés avec TypeScript étant un cookie heureux: exemple mentionné ici ( Remarque: dans mon cas, le mappage du composant se trouve dans un fichier conteneur séparé, mais l'idée est la même.).

Si quelqu'un pense que c'est une mauvaise solution, je suis ouvert à tout changement et à toute idée. En ce moment, je suis juste content que mon code ait cessé de se plaindre.

type Styles = 'foo';
const styles: StyleRulesCallback<Styles> = (theme: Theme) => ({
    foo: {
        position: 'relative',
    }
});

interface Props {
  something: string;
}

class Sidebar extends React.Component<Props & WithStyles<Styles>> {
    render() {
        const { classes, something } = this.props;

        return (
                    <div className={classes.foo}>{something}</div>
        );
    }
}

export default withStyles(styles)<Props>(Sidebar);

Je ne veux pas créer de nouveau problème, mais j'ai essayé tout ce que j'ai vu dans la documentation, l'exemple et les problèmes passés, même avec la recomposition, mais je ne peux pas faire fonctionner mon composant lorsque j'y ajoute des propriétés.
Et les ressources que j'ai trouvées concernent principalement les anciennes versions de TS, MUI ou même React.

Voici mon composant :

import React from 'react';
import AppBar from 'material-ui/AppBar';
import { withStyles, WithStyles, StyleRulesCallback } from 'material-ui/styles';

const styles: StyleRulesCallback<'positionFixed'> = () => ({
  positionFixed: {
    top: 'auto',
    bottom: 0,
  },
});

const decorate = withStyles(styles);

interface Props {
   someProp: string;
};

export const BottomNav = decorate<Props>(
  class extends React.Component<Props & WithStyles<'positionFixed'>, {}> {
    render() {
      return (
        <AppBar />
      );
    }
  }
);

export default BottomNav;

Et l'erreur est :

TS2322: Type '{}' is not assignable to type 'IntrinsicAttributes & Props & StyledComponentProps<"positionFixed"> & { children?: ReactNode; }'.
  Type '{}' is not assignable to type 'Props'.
    Property 'someProp' is missing in type '{}'.

Je suis assez débutant avec TS, mais je trouve la page de documentation et l' exemple assez confus et/ou incomplets.

Si vous avez une idée, merci ;-)

@otroboe omettez -vous le code qui a été signalé avec l'erreur ? Est-ce que ça ressemble à ça?

<BottomNav />

Si c'est le cas, le problème est que vous devez fournir le prop someProp (qui est requis selon votre définition de Props ):

<BottomNav someProp="foo" />

Honte à moi... Oh, honte à moi.
J'étais tellement concentré sur l'intégration de TS que j'ai oublié de regarder autour de moi et de prendre du recul.

Merci beaucoup @pelotom :sourire:

@otroboe Supprimez également la duplication de chaîne...

type Styles = 'positionFixed';

J'aurais aimé que celui-ci soit plus facile cependant...

Oui je l'ai fait aussi, merci :+1:

Je viens de rencontrer ce même problème, mais il s'avère que cela ne se produit que si j'ai initialisé l'objet styles dans le même fichier que ma classe ou fonction. Sinon, si j'importe les styles d'un autre fichier, je n'obtiens pas cette erreur.

Une idée de pourquoi cela se produit?

@nishmeht7 pouvez-vous publier un extrait autonome ?

@pelotom Je viens de travailler à en créer un, et cela fonctionne bien dans mon environnement de bac à sable. Je travaille actuellement sur une grande application et je suis toujours sur la version mui 1.2.2, tandis que ma version sandbox env est la dernière. Je suppose donc qu'une fois les versions mises à niveau, je ne pourrai plus reproduire mon erreur.

J'ai suivi l'exemple d'un formulaire de base de https://material-ui.com/demos/selects/ mais j'ai reçu des plaintes selon lesquelles theme n'a pas root (en utilisant le dernier tapuscrit et le dernier matériel- ui) et aucune classe n'était appliquée à l'élément form . J'ai essayé de suivre la discussion ci-dessus, mais cela ne semble pas concluant. Et en effet, la liste des classes héritées manquait le nom de classe généré pour form . Si j'ai ajouté le nom de classe généré manuellement (trouvé dans withStyles avec console.log(theme) dans les outils de développement inspecter les éléments, tout va bien, donc apparemment la classe était générée correctement. N'était pas transmis par withStyles au form élément

Je suis donc revenu aux styles pour le moment jusqu'à ce que cela soit réglé :

<form style = {{display:'flex',flexWrap:'wrap'}} autoComplete="off">

@HenrikBechmann Avez-vous essayé de suivre la documentation sur les styles pour le tapuscrit ? Dans le passé, cela m'a été très utile. https://material-ui.com/guides/typescript/

Merci @lookfirst ! J'ai regardé (mais pas en premier :-) ) à ce doc, et utilisé

export default withStyles({
  root: {
    display: 'flex',
    flexWrap: 'wrap',
  },
})(BaseForm)

(en passant l'objet plutôt que la fonction)

... qui ont à la fois évité les erreurs de saisie et permis l'injection de la classe générée.

Espérons que les autres conseils vous aideront avec des constructions plus complexes.

J'ai également confirmé que la structure plus complexe de la fonction styles fonctionne (injecte un className généré dans form ):

import React from 'react'

import { withStyles, createStyles, Theme } from '@material-ui/core/styles'

/*
    patterned after first demo https://material-ui.com/demos/selects/ for 3.03
    use Typsecript fixes from here: https://material-ui.com/guides/typescript/
*/

const styles = (theme:Theme) => createStyles({
  root: {
    display: 'flex',
    flexWrap: 'wrap',
  },
})

class BaseForm extends React.Component<any,any> {

    render() {
        const { classes } = this.props

        return (
            <form className = {classes.root} autoComplete="off">
                {this.props.children}
            </form>
        )
    }
}

export default withStyles(styles)(BaseForm)

Edit : @eps1lon a souligné que cela WithStyles !

J'ai eu un certain succès en utilisant ReturnType<T> pour générer le ClassKey pour moi :

import * as React from 'react';

import withStyles, {
  StyledComponentProps, 
  StyleRulesCallback,
} from '@material-ui/core/styles/withStyles';

import { Theme } from '@material-ui/core/styles/createMuiTheme';

const overrideStyles = (theme: Theme) => ({
  root: {
    display: 'flex',
    flexDirection: 'column',
  },
});

type Props = StyledComponentProps<keyof ReturnType<typeof overrideStyles>>;

class MyComponent extends React.PureComponent<Props> {
  render() {
    return <div className={this.props.classes.root}></div>;
  }
}

export default withStyles(overrideStyles as StyleRulesCallback, {withTheme: true})(MyComponent);

En utilisant keyof ReturnType<typeof styleOverrides> comme StyledComponentProps ClassKey vous obtiendrez les clés de l'objet renvoyé par overrideStyles et vous évitera d'avoir à conserver une liste de ces clés manuellement . Le seul problème que j'ai remarqué est une erreur de type si je ne lance pas overrideStyles as StyleRulesCallback dans l'appel withStyles . Je ne suis pas sûr à 100% pourquoi. Je pense que c'est withStyles ne pas comprendre ce qu'est overrideStyles pour une raison quelconque.

Pour clarifier ce type plutôt élaboré, typeof styleOverrides résout en la fonction qui renvoie l'objet de style. ReturnType<T> vous procurera l'objet de style lui-même. keyof vous procurera les clés de l'objet style.

@chrislambe Vous devriez guide dactylographié . Vous ne devriez pas avoir besoin d'utiliser ReturnType etc. createStyles et WithStyles devraient suffire comme aides.

@eps1lon Oh hé, très cool ! Merci!

fwiw J'aime de plus en plus la paire createStyles/withStyles au fur et à mesure que je les utilise. Favorise un code ordonné, traite tous mes problèmes de style/dactylographe, et si je veux un css conditionnel local, je crée simplement des attributs de style local, qui ont bien sûr la priorité sur les classes.

Joli!!

En suivant le guide dactylographié avec @material-ui/ [email protected], j'obtiens Test does not have required attribute classes sur :

import React from 'react'
import { Theme, WithStyles, withStyles, createStyles } from '@material-ui/core/styles'

const styles = (theme: Theme) => createStyles({
  root: {
    color: theme.palette.action.active
  },
})

interface Props extends WithStyles<typeof styles> {
  asd: boolean
}

class TestComponent extends React.Component<Props> {

  render() {
    const { classes } = this.props

    return (
      <div className={classes.root}>
      </div>
    )
  }
}

const Test = withStyles(styles)(TestComponent)

const a = () => <Test asd={true}/>

@valoricDe Avez-vous résolu votre problème ?

@TrejGun Je viens de vérifier. Avec un composant fonctionnel et @material-ui/ [email protected] je n'ai pas ce problème

Je ne comprends pas vraiment.
Suivez les documents ici : https://material-ui.com/guides/typescript/#augmenting -your-props-using-withstyles
semble simplement entraîner le problème de ce problème d'origine. Lorsque vous utilisez le composant quelque part, le typescript vous demande de _passer_ la propriété classes en tant qu'accessoire au lieu de réaliser qu'elle va être _injectée_ par withStyles.

Je lis ces numéros depuis quelques heures maintenant et je ne comprends pas vraiment. Toute aide serait si gentille à ce stade.

Concernant cette suggestion ci-dessus

@cfilipov lors de la décoration d'une classe de composant, vous devez utiliser StyledComponentProps au lieu de WithStyles , et si en mode de vérification de type strict, vous devez utiliser l'opérateur d'assertion non nul ! pour extraire les champs de classes . C'est un compromis pour permettre l'utilisation de withStyles comme décorateur de classe. Les décorateurs de classe dans TypeScript souffrent de la limitation selon laquelle leur type de retour doit correspondre au type d'argument. Compte tenu de ces limitations, une seule option est possible :

  1. ne supporte pas l'utilisation de withStyles comme décorateur de classe
  2. exiger que vous passiez un accessoire factice classes lors de la construction d'un élément du type de composant décoré (le compromis précédent, qui était sans doute plus ennuyeux )
  3. exiger que classes soit considéré comme nullable à l'intérieur du composant, vous obligeant à utiliser l'opérateur ! lors de l'accès à ses champs ( le compromis actuel )

Je recommanderais fortement que si votre composant n'a pas d'état, vous utilisiez un composant fonctionnel sans état, qui nécessitera moins d'annotations de type et sera plus sûr pour le type :

export default withStyles(styles)<Props>(({ classes, message }) => (
  <div className={classes.main}>
    <div className={classes.foo}>
      Hello World! {message}
    </div>
  </div>
));

Comment puis-je découvrir comment utiliser StyledComponentProps ? Il semble que je passe juste des chaînes de clés définies dans l'objet styles.

Mais les docs nous disent de faire quelque chose qui ne fonctionnera tout simplement pas ? Qu'est-ce que je rate? J'aimerais utiliser https://material-ui.com/guides/typescript/#augmenting -your-props-using-withstyles...

Est-ce possible?

@valoricDe , Comment avez-vous fait le composant fonctionnel qui n'avait pas ce problème

@TrejGun Je viens de vérifier. Avec un composant fonctionnel et @material-ui/ [email protected] je n'ai pas ce problème

J'essaye quelque chose comme ça :

```import React, { ChangeEvent, Component, Dispatch } de "react" ;
importer des PropTypes à partir de "prop-types" ;
importer { connecter } de "react-redux" ;
importer { Grid, FormControlLabel, Theme, createStyles, withStyles, Radio, WithStyles } depuis "@material-ui/core" ;
importer le montant de "./Amount" ;
importer { onPastDueFormFieldChange } de "../../store/actions/selectPaymentAmountActions" ;

const styles = (thème : Thème) =>
createStyles({
montant: {
alignSelf: "centre",
},
});

interface OwnProps étend WithStyles{}

interface StateProps {
pastDue ? : nombre ;
pastDueOrTotalOrOther : chaîne ;
}

interface DispatchProps {
onPastDueFormFieldChange: OnPastDueFormFieldChange;
}

tapez Props = StateProps & DispatchProps & OwnProps;

const PastDueFormField = withStyles(styles)(
({ classes, pastDue, pastDueOrTotalOrOther, onPastDueFormFieldChange } : accessoires) => (
value="pastDue"
checké={pastDueOrTotalOrOther === "pastDue"}
onChange={onPastDueFormFieldChange}
label="En retard :"
contrôle={ }
/>




),
);

const mapStateToProps = (état : RootState) : StateProps => ({
pastDue : state.customerData.balanceDue.pastDue,
pastDueOrTotalOrOther : state.customerPaymentsForm.pastDueTotalOrOther,
});

exporter la connexion par défaut(
mapStateToProps,
{ onPastDueFormFieldChange },
)(PastDueFormField);

When I use this component I have this error:
```import PastDueFormField
Property 'classes' is missing in type '{}' but required in type 'Readonly<PropsWithChildren<Pick<Pick<Props, "pastDue" | "pastDueOrTotalOrOther" | "onPastDueFormFieldChange"> & StyledComponentProps<"amount">, "classes" | "innerRef"> & OwnProps>>'

@yehudamakarov Essayez d'abord votre code sans react-redux et ajoutez connect lorsque tout fonctionne comme prévu. Il est incroyablement difficile d'avoir une bonne vue d'ensemble quand quel accessoire est injecté.

Lorsque je rencontre ces problèmes, je vais

  1. tapez d'abord mes accessoires de composant
  2. vérifiez si tout est requis comme prévu, c'est-à-dire obtenez missing props
  3. appliquer hoc
  4. voir si dactylographié reconnaissait chaque accessoire injecté
  5. répéter 3 jusqu'à ce que tous les hocs soient appliqués.

Il promeut un code plus propre. Surtout en ce qui concerne l'ordre des opérations. Vous mélangez actuellement withStyles et connect sans séparation des préoccupations.

Merci beaucoup Sébastien.
J'ai résolu mon problème en ne passant simplement pas d'arguments génériques pour me connecter. J'ai sorti le morceau <StateProps ...> .

Je pense que ces arguments génériques perturbaient mon interface OwnProps qui étend WithStyles<>.

Étant donné que je transmets tout au composant de toute façon, la vérification de type que je reçois de mes Props est suffisante. Je ne sais pas pourquoi id a besoin des génériques connect<>.

Merci!

Voici à quoi cela ressemblerait de « décorer » une classe si les saisies étaient correctes :

type NonStyleProps = {
  text: string
};

const styles = {
  root: {
    backgroundColor: 'red'
  }
};

const DecoratedComponent = withStyles(styles)(
  class extends React.Component<NonStyleProps & WithStyles<'root'>> {
    render() {
      return (
        <div className={this.props.classes.root}>
          {this.props.text}
        </div>
      );
    }
  }
);

Et comment ajouter des thèmes (useTheme()) à l'intérieur comme :

const decorate = withStyles((theme: Theme) => ({
  root: {
    display: "flex"
  },
  appBar: {
    zIndex: theme.zIndex.drawer + 1,
    transition: theme.transitions.create(["width", "margin"], {
      easing: theme.transitions.easing.sharp,
      duration: theme.transitions.duration.leavingScreen
    })
  }
})
Cette page vous a été utile?
0 / 5 - 0 notes

Questions connexes

finaiized picture finaiized  ·  3Commentaires

sys13 picture sys13  ·  3Commentaires

mb-copart picture mb-copart  ·  3Commentaires

newoga picture newoga  ·  3Commentaires

reflog picture reflog  ·  3Commentaires