Material-ui: Typescript-Typfehler in der von withStyles() zurückgegebenen Komponente

Erstellt am 28. Sept. 2017  ·  55Kommentare  ·  Quelle: mui-org/material-ui

Wenn ich withStyles() hoc in Typoskript verwende, erhalte ich die folgende Fehlermeldung, wenn ich versuche, die zurückgegebene Komponente zu verwenden:

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] Ich habe die Ausgaben dieses Repositorys durchsucht und glaube, dass dies kein Duplikat ist.

Es scheint, dass diese Änderung an der Typdefinition mit diesem Problem zusammenhängt.

Erwartetes Verhalten

Angesichts des folgenden Komponentencodes App sollte ich in der Lage sein, die Komponente <App /> ohne den Typfehler zu verwenden, wie ich es in 1.0.0-beta.10 getan habe.

Aktuelles Verhalten

Angesichts des folgenden App Komponentencodes führt der Versuch, <App /> zu verwenden, zu dem oben genannten Fehler.

Der 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);

Kontext

Der Code funktionierte in 1.0.0-beta.10 einwandfrei, als ich auf 1.0.0-beta.12 aktualisierte, bekam ich den Typfehler.

In dem bereitgestellten Code-Schnipsel habe ich den keyof typeof styles Trick verwendet, damit ich nicht zweimal eine Liste von Klassennamen definieren muss (ich mag die Wiederholung nicht). Ich habe auch andere Variationen ausprobiert:

type ClassNames = WithStyles<keyof typeof styles>;

und machen Sie es auf die üblichere Weise (wie in style.spec.tsx zu sehen ):

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

Ich bekomme immer noch den gleichen Fehler.

Es scheint, dass die vorherige Typdefinition eine Komponente zurückgeben würde, deren Props-Typ StyledComponentProps die eine optionale classes Eigenschaft hat. Die neue Definition...

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

...den gleichen Typ C wie die Komponente zurückgibt, das bedeutet, dass die Übergabe von ClassNames die nicht als optional gekennzeichnet ist, an die zurückgegebene Komponente weitergegeben wird. Ich sehe hier die Verwendung von Partial<> was ich für einen unansehnlichen Hack halte.

Ihre Umgebung

| Technik | Version |
|-------------|---------|
| Material-UI | 1.0.0-beta.12 |
| Reagieren | 15.6.1 |
| Browser | Chrom 61.0.3163.100 |

discussion typescript

Hilfreichster Kommentar

Ich habe mit recompose gelöst

Beispiel

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>
        );
    }
}

Alle 55 Kommentare

@cfilipov wenn eine Komponentenklasse Dekoration sollten Sie verwenden StyledComponentProps anstelle von WithStyles , und wenn in strengem Typüberprüfungsmodus müssen Sie die Nicht-Null - Behauptung Operator verwenden ! zu extrahieren die Felder von classes . Dies ist ein Kompromiss, um die Verwendung von withStyles als Klassendekorateur zu ermöglichen. Klassendekoratoren in TypeScript leiden unter der Einschränkung, dass ihr Rückgabetyp mit dem Argumenttyp übereinstimmen muss. Angesichts dieser Einschränkungen ist nur eine Option möglich:

  1. unterstütze nicht die Verwendung von withStyles als Klassendekorateur
  2. erfordern, dass Sie eine Dummy- classes Prop übergeben, wenn Sie ein Element des dekorierten Komponententyps konstruieren (der vorherige Kompromiss, der wohl ärgerlicher war )
  3. erfordern, dass classes innerhalb der Komponente als NULL-fähig angesehen wird, was Sie zwingt, den ! Operator beim Zugriff auf ihre Felder zu verwenden ( der aktuelle Kompromiss ).

Ich würde dringend empfehlen, dass Sie, wenn Ihre Komponente keinen Zustand hat, eine zustandslose Funktionskomponente verwenden, die weniger Typanmerkungen erfordert und typsicherer ist:

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

Ich sehe hier die Verwendung von Partial<> erwähnt, was ich für einen unansehnlichen Hack halte.

Wenn Sie mein Follow-up zu diesem Kommentar lesen, werden Sie feststellen, dass Partial<> nicht erforderlich ist.

Wenn Sie mein Follow-up zu diesem Kommentar lesen, werden Sie feststellen, dass Partial<> nicht erforderlich ist.

Ich habe Ihren Kommentar zu Partial<> . Die Verwendung von StyledComponentProps Wesentlichen dasselbe (in dieser Definition wird Partial<> ). Mein Problem damit ist, dass jetzt auf Klassennamen mit ! zugegriffen werden muss (wie Sie bereits erwähnt haben). Ich denke, das Übergeben einer Dummy-Requisite von classes oder die Verwendung von ! sind beides schlechte Kompromisse.

Zur Verdeutlichung, ich denke, das Hauptproblem, das ich hier habe, ist die Wahl, eine Regression in das hoc einzuführen, um eine Einschränkung eines experimentellen Merkmals von Typoskript zu umgehen. Ich gebe zu, dass ich eine gewisse Voreingenommenheit habe, da ich mich nicht für Dekorateure interessiere, während andere dies eindeutig tun, aber der Kompromiss hier macht für mich keinen Sinn.

@cfilipov meine erste Überarbeitung der withStyles Typisierungen war die Wahl von Option (1), dh die Eingaben sowohl für Klassen- als auch für Funktionskomponenten vollständig korrekt zu machen, auf Kosten der Verwendung von withStyles als Klassendekorateur . Ich bekam dann Rückmeldung, dass die Verwendung der Decorator-Syntax eine beliebte Anfrage war, also wechselte ich zu Option (3). Ich freue mich, diese Entscheidung noch einmal zu überdenken; Auch ich würde die Typsicherheit der Unterstützung von Dekorateuren in ihrem aktuellen semifunktionalen Zustand vorziehen.

Ja, ich verstehe den Wunsch, eine beliebte Anfrage wie diese zu unterstützen. Ich möchte auch Dekorateure verwenden, aber ich stoße jedes Mal auf viele Probleme mit ihnen (außerhalb von mui), also habe ich persönlich beschlossen, sie nicht zu verwenden, bis sie fertig sind.

Es hört sich so an, als würden Sie meine Bedenken teilen und ich habe nicht viel hinzuzufügen, also können andere Leute hoffentlich Feedback in dieser Richtung geben, um es zu beeinflussen.

Ich bin von Beta.10 auf Beta.13 umgestiegen, um zu sehen, ob sich etwas geändert hat, und Ja, das ist ein echtes Problem. Um meine 2 Cent hier reinzuwerfen, sind Dekorateure für mich experimentell. Sie könnten offensichtlich in Zukunft geändert werden. Und bis dahin würde ich den 100% genauen Weg voll und ganz unterstützen. Ich hätte viel lieber eine kohärente Typsicherheit, als meine Typen zu hacken, damit die Dinge funktionieren.

8550 scheint ein weiterer Beweis dafür zu sein, dass die Leute dadurch verwirrt sind, und wir sollten in Betracht ziehen, @withStyles() als Dekorator (in TypeScript) zu unterstützen.

So würde es aussehen, eine Klasse zu "dekorieren", wenn wir die Eingaben richtig gemacht haben:

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 Aufgrund dieses Problems

@pelotom Vielen Dank, dass Sie uns zu diesem Thema withStyles seine Dekorationsunterstützung einstellen würde, um eine bessere Schriftsicherheit zu haben.

wir sollten in Betracht ziehen, @withStyles() nicht als Dekorator (in TypeScript) zu unterstützen.

@pelotom Ich persönlich bin für diese Änderung. @sebald Was willst du hier machen?

Es ist eine einfache Änderung; Ich ging voran und eröffnete eine PR, falls Sie damit gehen möchten 🙂

@pelotom würden die Eingaben noch funktionieren, wenn ich sie so verwenden würde?

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 keine 2 Typparameter mehr, und Sie sollten keinen Typparameter für Stile angeben müssen (er kann aus styles ). Du solltest stattdessen schreiben können

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

Wenn Sie die Typen für mapStateToProps und mapDispatchToProps angeben, kann ich Ihnen vielleicht zeigen, wie das für Ihr Beispiel aussehen würde.

tl;dr; Lass uns die Änderungen vornehmen und sehen, was die Gegenreaktion ist, denke ich


@oliviertassinari @pelotom ¯_(ツ)_/¯ Ich verwende keine Dekorateure, daher ist mir diese Änderung persönlich egal, da ich nicht betroffen bin. Aber es scheint, als ob sich viele Leute um dieses "Feature" kümmern. Deshalb haben wir es in erster Linie hinzugefügt. Das hat hier IMHO Priorität.

Ich bin sehr zufrieden mit den Änderungen von withStyles , aber wenn Sie sich andere funktionale Bibliotheken ansehen, wie ramda oder recompose , sind die Eingaben nicht so streng. sie sind auch nicht super typsicher. Oft müssen Sie ein Generic übergeben, das den Rückgabewert einer Funktion darstellt. Nicht schön, aber es wird für 99,9% der Benutzer funktionieren.

Warum können wir nicht die alten Schreibweisen zurückbringen, die für die Leute, die Dekorateure verwenden, funktioniert haben? Da es zwei Generika gab, können wir möglicherweise beide Typisierungen nebeneinander haben.

Außerdem bin ich etwas verwirrt, was die Probleme der Leute mit Dekorateuren sind (in Bezug auf "funktioniert nicht"). Libs wie Angular und https://nestjs.com/ nutzen sie doch stark. In unserem Fall könnten die Leute einfach WithStyles zu den Requisiten hinzufügen und es geht ihnen gut.

@sebald

Warum können wir nicht die alten Schreibweisen zurückbringen, die für die Leute, die Dekorateure verwenden, funktioniert haben? Da es zwei Generika gab, können wir möglicherweise beide Typisierungen nebeneinander haben.

Ich bin mir nicht sicher was du meinst. Es gab nie ein Tippen, das es den Leuten ermöglichte, Dekorateure schmerzlos zu verwenden. Die erste Implementierung litt unter #8267, was darin bestand, dass Sie kein Element einer dekorierten Komponente konstruieren konnten, ohne einen Dummy classes prop zu übergeben, zB <StyledComp classes={{} as any} /> . Die zweite (aktuelle) Implementierung leidet unter dem umgekehrten Problem, dass classes als potentiell undefined innerhalb der Komponentenklasse angesehen wird. Wenn Sie TypeScript-Dekoratoren in ihrer aktuellen Form verwenden möchten, sind dies Ihre einzigen 2 Optionen; Wähle dein Gift.

Die dritte Möglichkeit besteht darin, den richtigen Typ zu verwenden, sodass classes innerhalb der Klasse definiert ist, aber nicht als Requisite übergeben werden muss. Um beide Bedingungen zu erfüllen, müssen Sie Dekorateure aufgeben.

@pelotom Ja, tut mir leid. Du hast recht. Ist wirklich nicht mein Tag... 🤐 Also lasst uns verschmelzen!

@sebald

Außerdem bin ich etwas verwirrt, was die Probleme der Leute mit Dekorateuren sind (in Bezug auf "funktioniert nicht"). Libs wie Angular und https://nestjs.com/ nutzen sie doch stark.

Ich bin mir nicht sicher, wie sie in Angular verwendet werden, aber es gibt sicherlich Anwendungsfälle, in denen Dekorateure schmerzlos verwendet werden können. Wenn der Dekorateur den Typ der Klasse, die er dekoriert, nicht ändern muss, funktionieren sie im Grunde gut. Das ist nicht die Situation, die wir hier haben; withStyles muss den Typ der Komponente ändern, die es dekoriert.

@pelotom Ja, genau. Es ist nur die Mutation, die schlecht ist. Tatsächlich könnte die Art und Weise, wie TS Dekoratoren derzeit implementiert, sogar für die Angular-Benutzer gut sein, da die Dekoratoren AFAIK Verträge mit dem Framework abschließen, wie z "...Gott selbst wenn ich darüber schreibe, fühle ich mich

@pelotom Der Grund, warum ich die Typen so habe, wie ich es tue, ist die injiziertenProps in meinem Beispiel sind die Typen, die von der Komponente benötigt werden, um zu funktionieren. Die Verbindungstypen von react-redux müssen die von Props sein, die von mapStateToProps stammen, und DispatchProps, die von mapDispatchToProps stammen .

Ganz am Ende müssen die injiziertenProps vorhanden sein, damit meine übergeordnete Komponente weiß, dass ich sie injizieren muss oder mein Projekt nicht kompiliert wird. (Das ist was ich will). Wird diese Änderung wieder auf diese Art von typeSafety migriert?

@marcusjwhelan noch einmal, wenn Sie ein vollständiges (aber minimales) Beispiel bereitstellen können, das in Beta 10 kompiliert wurde, kann ich Ihnen zeigen, wie Sie migrieren. AFAIK soll die neue Version genauso ausdrucksstark und typsicherer sein als bisher.

@pelotom Dumme Frage, gibt es eine Möglichkeit, benachrichtigt zu werden, sobald eine neue Version fertig ist?

@wcandillon Folgen Sie uns auf Twitter.

@pelotom Ich habe oben ein Beispiel

Bearbeiten

Ich habe es herausgefunden.

Ich steige etwas spät in diese Diskussion ein, aber ich habe einen ähnlichen Fehler wie hier erwähnt gesehen und muss noch feststellen, wie ich ihn korrigieren kann. Ich verwende [email protected] und [email protected] .

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

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

Die Fehlermeldung, die ich in diesem speziellen Fall erhalte, lautet:

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 '{}'.

beim Dekorieren einer Komponentenklasse sollten Sie StyledComponentProps anstelle von WithStyles verwenden

@pelotom - gibt es dafür irgendwo ein Beispiel? Ich habe eine Menge Probleme zu bestimmen, wie eine zustandsbehaftete Komponentenklasse in TypeScript gestaltet wird.

@iamjem es ist ein wenig schwer zu sagen, da Sie styles , aber es sieht so aus, als ob das erste Problem darin besteht, dass Sie in styles mehr Klassenschlüssel erwähnt haben, als Sie in WithStyles<...> erwähnen

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

es sollte sich um das erste Problem kümmern. Dann sieht es so aus, als gäbe es ein zweites Problem, nämlich dass der resultierende Typ von LoginForm ist

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

was offensichtlich nicht richtig ist; es sieht so aus, als ob das Fehlen von Nicht-Stil-Requisiten das Typensystem verwirren würde. Sie können dabei helfen, indem Sie explizit angeben, was die Nicht-Stil-Requisiten sind, indem Sie {} als Typargument übergeben:

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

Tut mir leid, dass es so kompliziert ist, ich wünschte, ich wüsste einen einfacheren Weg, dieses Zeug zum Laufen zu bringen!

Das hat funktioniert! Danke für die schnelle Hilfe @pelotom. Ich benutze React schon lange, bin aber erst vor kurzem in Material-ui gesprungen und dachte, ich probiere mal Typescript aus, wenn ich schon dabei bin. Unnötig zu erwähnen, dass es einige Grenzfälle gibt, in denen es schwierig ist zu sagen, wie man Typescript glücklich macht.

Ich habe mit recompose gelöst

Beispiel

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>
        );
    }
}

Ich kämpfte mit diesem Problem (und #8704), ohne dass in den letzten Tagen ein klares Ergebnis erzielt wurde. Dann habe ich den Rat von @pelotom angenommen :

Sie sollten StyledComponentProps anstelle von WithStyles

und suchte auf GitHub nach ähnlichen Möglichkeiten, dies zu lösen. Und ich habe EIN funktionierendes Beispiel gefunden 😂. Es ist jedoch gut und hat mein Problem gelöst - separater Container und Komponente, wobei TypeScript ein glückliches Cookie ist: hier erwähntes Beispiel ( Hinweis: In meinem Fall befindet sich die Komponentenzuordnung in einer separaten Containerdatei, aber die Idee ist die gleich.).

Wenn jemand denkt, dass dies eine schlechte Lösung ist, bin ich für Änderungen und Ideen offen. Im Moment bin ich nur froh, dass sich mein Code nicht mehr beschwert.

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);

Ich möchte kein neues Problem erstellen, aber ich habe alles versucht, was ich in der Dokumentation oder im Beispiel gesehen habe, und Probleme bestanden, sogar mit Neuzusammenstellung, aber ich kann meine Komponente nicht zum Laufen bringen, wenn ich ihr einige Eigenschaften hinzufüge.
Und die Ressourcen, die ich gefunden habe, sind meistens mit älteren Versionen von TS, MUI oder sogar React.

Hier ist meine Komponente:

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;

Und der Fehler ist:

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 '{}'.

Ich bin ein ziemlicher Anfänger mit TS, aber ich finde die Dokumentationsseite und das Beispiel ziemlich verwirrend und / oder nicht vollständig.

Falls ihr eine Idee habt, danke ;-)

@otroboe lässt du den Code weg, der tatsächlich mit dem Fehler gekennzeichnet wurde? Sieht es so aus?

<BottomNav />

In diesem Fall müssen Sie die Requisite someProp angeben (die gemäß Ihrer Definition von Props erforderlich ist):

<BottomNav someProp="foo" />

Schande über mich... Oh, Schande über mich.
Ich war so auf die TS-Integration fokussiert, dass ich vergessen habe, mich umzusehen und ein paar Schritte zurückzugehen.

Vielen Dank @pelotom :smile:

@otroboe Entfernen Sie auch die

type Styles = 'positionFixed';

Wünschte aber, das wäre einfacher...

Ja habe ich auch gemacht, danke :+1:

Ich hatte gerade das gleiche Problem, aber es stellt sich heraus, dass es nur auftritt, wenn ich das Stilobjekt in derselben Datei wie meine Klasse oder Funktion initialisiert habe. Alternativ, wenn ich die Stile aus einer anderen Datei importiere, erhalte ich diese Fehlermeldung nicht.

Irgendeine Ahnung, warum das passiert?

@nishmeht7 kannst du ein eigenständiges Snippet posten?

@pelotom Ich habe gerade daran gearbeitet, einen zu

Ich folgte dem Beispiel eines einfachen Formulars von https://material-ui.com/demos/selects/ , bekam aber Beschwerden, dass theme root (mit dem neuesten Typoskript und Material- ui) und es wurde keine Klasse auf das form Element angewendet. Ich habe versucht, der obigen Diskussion zu folgen, aber es scheint nicht schlüssig. Und tatsächlich fehlte in der Liste der geerbten Klassen der generierte Klassenname für form . Wenn ich den generierten Klassennamen manuell hinzugefügt habe (zu finden in withStyles mit console.log(theme) in den Dev Tools inspect elements), ist alles in Ordnung, also wurde die Klasse anscheinend korrekt generiert. Wurde nicht durch withStyles an die form Element aber ziemlich verwirrend.

Also bin ich vorerst zu Stilen zurückgekehrt, bis dies sortiert ist:

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

@HenrikBechmann Haben Sie versucht, die befolgen ? In der Vergangenheit hat es mir sehr geholfen. https://material-ui.com/guides/typescript/

Danke @lookfirst! Ich habe mir das Dokument angeschaut (wenn auch nicht zuerst :-) ) und verwendet

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

(Übergeben des Objekts statt der Funktion)

... die sowohl die Typoskriptfehler vermieden als auch das Einschleusen der generierten Klasse ermöglicht hat.

Hoffentlich helfen die anderen Tipps dort bei komplexeren Konstrukten.

Ich habe auch bestätigt, dass die komplexere Struktur für die Funktion styles funktioniert (injiziert ein generiertes className in 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 hat darauf hingewiesen, dass dies bei der Verwendung von WithStyles unnötig ist!

Ich hatte einige Erfolge mit ReturnType<T> , um die ClassKey für mich zu generieren:

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);

Wenn Sie keyof ReturnType<typeof styleOverrides> als StyledComponentProps ClassKey , erhalten Sie die Schlüssel aus dem Objekt, das von overrideStyles und erspart Ihnen, eine Liste dieser Schlüssel manuell zu führen . Der einzige Fehler, der mir aufgefallen ist, ist ein Typfehler, wenn ich overrideStyles as StyleRulesCallback im withStyles Aufruf nicht umsetze. Ich bin mir nicht 100% sicher warum. Ich denke, es ist withStyles aus irgendeinem Grund nicht zu verstehen, was overrideStyles ist.

Um diesen ziemlich komplizierten Typ zu verdeutlichen, wird typeof styleOverrides in die Funktion aufgelöst, die das Stilobjekt zurückgibt. ReturnType<T> ruft das Stilobjekt selbst ab. keyof holt dir die Schlüssel aus dem Style-Objekt.

@chrislambe Sie sollten sich die Typoskript-Anleitung ansehen . Sie sollten nicht ReturnType usw. verwenden müssen. createStyles und WithStyles sollten als Helfer ausreichen.

@eps1lon Oh hey, sehr cool! Vielen Dank!

fwiw Ich mag das createStyles/withStyles-Paar immer mehr, wenn ich es verwende. Fördert aufgeräumten Code, kümmert sich um alle meine Styling- / Typoskript-Probleme, und wenn ich lokales bedingtes CSS möchte, erstelle ich einfach lokale Stilattribute, die natürlich Vorrang vor Klassen haben.

Schön!!

Nach der Typoskript-Anleitung mit @material-ui/ core @ Test does not have required attribute classes auf:

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}/>

@aaronlifton2
Folgen Sie bitte dem

@valoricDe Hast du dein Problem gelöst?

@TrejGun Ich habe gerade nachgesehen. Mit einer Funktionskomponente und @material-ui/ core @

Ich verstehe nicht wirklich.
Folgen Sie den Dokumenten hier: https://material-ui.com/guides/typescript/#augmenting -your-props-using-withstyles
scheint nur das Problem dieses ursprünglichen Problems zu ergeben. Wenn Sie die Komponente irgendwo verwenden, fordert Typescript Sie auf, die Klasseneigenschaft als Requisite zu _übergeben_, anstatt zu erkennen, dass sie von withStyles _injiziert_ wird.

Ich lese diese Ausgaben jetzt seit ein paar Stunden und ich verstehe sie nicht wirklich. Jede Hilfe wäre an dieser Stelle so nett.

Zu diesem Vorschlag oben

@cfilipov wenn eine Komponentenklasse Dekoration sollten Sie verwenden StyledComponentProps anstelle von WithStyles , und wenn in strengem Typüberprüfungsmodus müssen Sie die Nicht-Null - Behauptung Operator verwenden ! zu extrahieren die Felder von classes . Dies ist ein Kompromiss, um die Verwendung von withStyles als Klassendekorateur zu ermöglichen. Klassendekoratoren in TypeScript leiden unter der Einschränkung, dass ihr Rückgabetyp mit dem Argumenttyp übereinstimmen muss. Angesichts dieser Einschränkungen ist nur eine Option möglich:

  1. unterstütze nicht die Verwendung von withStyles als Klassendekorateur
  2. erfordern, dass Sie eine Dummy- classes Prop übergeben, wenn Sie ein Element des dekorierten Komponententyps konstruieren (der vorherige Kompromiss, der wohl ärgerlicher war )
  3. erfordern, dass classes innerhalb der Komponente als NULL-fähig angesehen wird, was Sie zwingt, den ! Operator beim Zugriff auf ihre Felder zu verwenden ( der aktuelle Kompromiss ).

Ich würde dringend empfehlen, dass Sie, wenn Ihre Komponente keinen Zustand hat, eine zustandslose Funktionskomponente verwenden, die weniger Typanmerkungen erfordert und typsicherer ist:

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

Wie finde ich heraus, wie man StyledComponentProps ? Es scheint, dass ich nur Strings der im Styles-Objekt definierten Schlüssel übergebe.

Aber die Docs sagen uns, dass wir etwas tun sollen, das einfach nicht funktioniert? Was vermisse ich? Ich möchte https://material-ui.com/guides/typescript/#augmenting -your-props-using-withstyles verwenden...

Ist das möglich?

@valoricDe , Wie haben Sie die Funktionskomponente erstellt, die dieses Problem nicht hatte

@TrejGun Ich habe gerade nachgesehen. Mit einer Funktionskomponente und @material-ui/ core @

Ich versuche so etwas:

```import React, { ChangeEvent, Component, Dispatch } from "react";
Importieren Sie PropTypes von "prop-types";
import {connect} from "react-redux";
import { Grid, FormControlLabel, Theme, createStyles, withStyles, Radio, WithStyles } from "@material-ui/core";
Betrag aus "./Betrag" importieren;
import { onPastDueFormFieldChange } from "../../store/actions/selectPaymentAmountActions";

const Styles = (Thema: Thema) =>
createStyles({
betragen: {
alignSelf: "zentrieren",
},
});

Schnittstelle OwnProps erweitert WithStyles{}

Schnittstelle StateProps {
pastDue?: Zahl;
pastDueOrTotalOrOther: Zeichenfolge;
}

Schnittstelle DispatchProps {
onPastDueFormFieldChange: OnPastDueFormFieldChange;
}

type Props = StateProps & DispatchProps & OwnProps;

const PastDueFormField = withStyles(styles)(
({ Klassen, pastDue, pastDueOrTotalOrOther, onPastDueFormFieldChange }: Props) => (
value="pastDue"
check={pastDueOrTotalOrOther === "pastDue"}
onChange={onPastDueFormFieldChange}
label="Überfällig:"
Kontrolle={ }
/>




),
);

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

Standardverbindung exportieren(
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 Probieren Sie zuerst react-redux und fügen Sie connect wenn alles wie erwartet funktioniert. Es ist unglaublich schwer, einen guten Überblick zu bekommen, wann welche Stütze eingespritzt wird.

Wenn ich auf diese Probleme stoße, werde ich

  1. Geben Sie zuerst meine Komponenten-Requisiten ein
  2. Überprüfen Sie, ob alles wie erwartet erforderlich ist, dh erhalten Sie missing props
  3. Bewerben hoc
  4. Sehen Sie, ob das Typoskript jede injizierte Requisite erkannt hat
  5. Wiederholen Sie 3, bis alle Hocs angewendet wurden.

Es fördert saubereren Code. Vor allem in Bezug auf die Reihenfolge der Operationen. Sie mischen derzeit withStyles und connect ohne eine Trennung der Bedenken.

Vielen Dank Sebastian.
Ich habe mein Problem gelöst, indem ich einfach keine generischen Argumente übergeben habe, um eine Verbindung herzustellen. Ich habe das Stück <StateProps ...> .

Ich denke, diese generischen Argumente haben meine OwnProps-Schnittstelle durcheinander gebracht, die WithStyles<> erweitert.

Da ich sowieso alles an die Komponente übergebe, ist die Typprüfung, die ich von meinen Props bekomme, ausreichend. Nicht sicher, warum ich die Connect<>-Generika brauche.

Vielen Dank!

So würde es aussehen, eine Klasse zu "dekorieren", wenn wir die Eingaben richtig gemacht haben:

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>
      );
    }
  }
);

Und wie man Themen (useTheme()) hinzufügt wie:

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
    })
  }
})
War diese Seite hilfreich?
0 / 5 - 0 Bewertungen

Verwandte Themen

ryanflorence picture ryanflorence  ·  3Kommentare

TimoRuetten picture TimoRuetten  ·  3Kommentare

FranBran picture FranBran  ·  3Kommentare

iamzhouyi picture iamzhouyi  ·  3Kommentare

rbozan picture rbozan  ·  3Kommentare