Definitelytyped: Implementieren von defaultProps mit strengen ts 2.0-Nullprüfungen

Erstellt am 30. Sept. 2016  ·  50Kommentare  ·  Quelle: DefinitelyTyped/DefinitelyTyped

Standardeigenschaften scheinen derzeit mit aktivierten strictNullChecks nicht gut zu funktionieren. Zum Beispiel:

interface TestProps { x?: number}

class Test extends React.Component<TestProps, null> {

    static defaultProps =  {x: 5};

    render() {
        const x: number = this.props.x;
        return <p>{x}</p>;
    }
}

Fehler bei error TS2322: Type 'number | undefined' is not assignable to type 'number' obwohl dies zur Laufzeit garantiert funktioniert.

Im Moment scheinen defaultProps und Props immer als derselbe Typ behandelt zu werden, aber sie sind tatsächlich fast nie derselbe Typ, da optionale Felder in Props durch erforderliche Werte in DefaultProps überschrieben werden sollten.

Was wäre, wenn es sowas gäbe...

class ComponentWithDefaultProps<P, D, S> {
    props: P & D & {children?: React.Children};
}

das ist identisch mit der bestehenden Typisierung von React.Component, abgesehen von der Art der Requisiten?

Hilfreichster Kommentar

Wenn jemand eine gute Lösung für Typen und defaultProps hat, bin ich ganz Ohr. Das machen wir aktuell:

interface Props {
  firstName: string;
  lastName?: string;
}

interface DefaultProps {
  lastName: string;
}

type PropsWithDefaults = Props & DefaultProps;

export class User extends React.Component<Props> {
  public static defaultProps: DefaultProps = {
    lastName: 'None',
  }

  public render () {
    const { firstName, lastName } = this.props as PropsWithDefaults;

    return (
      <div>{firstName} {lastName}</div>
    )
  }
}

Alle 50 Kommentare

Da die Standardprops zur Laufzeit festgelegt werden, bin ich mir nicht sicher, ob es eine andere Möglichkeit gibt, dies gut zu handhaben, als eine Typzusicherung. (Natürlich könnten Sie die strengen Nullprüfungen auch einfach deaktivieren.)

So können Sie es in Ihrem Beispiel möglicherweise umgehen:

interface TestProps { x?: number}

class Test extends React.Component<TestProps, null> {

    static defaultProps =  {x: 5};

    render() {
        const x: number = (this.props.x as number);
        return <p>{x}</p>;
    }
}

Siehe https://www.typescriptlang.org/docs/handbook/basic-types.html#type -assertions

Wenn es eine anmutigere Art gibt, damit umzugehen, würde ich es gerne hören.

Haftungsausschluss: Ich benutze TypeScript seit ungefähr drei Tagen, bin müde und habe wahrscheinlich keine Ahnung, wovon ich spreche.

+1000 beim Aktualisieren der Typdefinitionsdatei, um drei generische Typdefinitionen aufzunehmen.

Dies war früher ohne ---strictNullChecks in Ordnung, aber jetzt wird es definitiv ein Problem für viele Komponentenklassen sein.

Flow implementiert auch eine ähnliche Klassenimplementierung aufgrund der Natur der strengen Nulltypprüfung.
https://github.com/facebook/flow/blob/master/lib/react.js#L16
https://github.com/facebook/flow/blob/master/lib/react.js#L104 -L105

Scheint, als hätten wir hier nicht viele Optionen, außer darauf zu warten, dass https://github.com/Microsoft/TypeScript/issues/2175 gelöst wird, um ein drittes Generikum hinzuzufügen.
Ich glaube nicht, dass eine solche (Breaking) Change (ich meine class Component<P, S, D> ) von Rezensenten genehmigt werden kann.
@johnnyreilly @bbenezech @pzavolinsky habt ihr eine Meinung dazu?

@r00ger stimmte zu. Das Ändern der Definition ist zu störend.

Hat jemand darüber nachgedacht, Partial zu verwenden?

Wie in:

    interface ComponentClass<P> {
-        defaultProps?: P;
+        defaultProps?: Partial<P>;
    }

Kümmern Sie sich nicht um das Partial Zeug oben.

Partial löst nur, wie das Problem mit partiellen propTypes deklariert wird. Innerhalb von render ist lastName immer noch vom Typ string | undefined . Um dies zu umgehen, müssen Sie den String mit as oder ! umwandeln, wie unten gezeigt. Es funktioniert, ist aber nicht ideal.

interface IUser {
    firstName: string
    lastName?: string
}
export class User extends React.Component<IUser, {}> {
    public static defaultProps: Partial<IUser> = {
        lastName: 'None',
    }

    public render () {
        const { firstName, lastName } = this.props
        // error
        lastName.toUpperCase()

        return (
            <div>{firstName} {lastName}</div>
        )
    }
}

Ich habe gerade angefangen, TS zu verwenden. Vermisse ich etwas?

Wenn jemand eine gute Lösung für Typen und defaultProps hat, bin ich ganz Ohr. Das machen wir aktuell:

interface Props {
  firstName: string;
  lastName?: string;
}

interface DefaultProps {
  lastName: string;
}

type PropsWithDefaults = Props & DefaultProps;

export class User extends React.Component<Props> {
  public static defaultProps: DefaultProps = {
    lastName: 'None',
  }

  public render () {
    const { firstName, lastName } = this.props as PropsWithDefaults;

    return (
      <div>{firstName} {lastName}</div>
    )
  }
}

+1
Ich kämpfe derzeit mit diesem Problem.

+1

+1

Zusätzlich zum Hinzufügen des dritten Typparameters benötigen Sie die Möglichkeit, Requisiten mit den standardmäßigen Requisiten zu vergleichen. Glücklicherweise ist dies ab TS 2.4 jetzt möglich! Siehe https://github.com/Microsoft/TypeScript/issues/12215#issuecomment -319495340

Meiner Meinung nach ist das Hinzufügen eines dritten Parameters ein großes Nein, nein, auch das Flow-Team wusste das und hat das kürzlich zum Besseren geändert. Es sollte in der Verantwortung des Typenprüfers liegen, zu wissen, wie man mit solchen Dingen umgeht.

Versteh mich nicht falsch, ich liebe Typescript, aber seit Flow 0.53 muss ich sagen, dass es für die React-Entwicklung überlegen ist https://medium.com/flow-type/even-better-support-for-react-in-flow- 25b0a3485627

@Hotell Flow hat drei Typparameter für React.Component - gemäß dem Medium-Artikel, den Sie mit Flow verknüpft haben, können Klassentypparameter aus den Unterklassenanmerkungen abgeleitet werden - eine nette Funktion auf Sprachebene, die TS nicht unterstützt, aber kein Typ -Erklärung Berücksichtigung AFAIK.

@aldendaniels

Flow hat drei Typparameter für React.Component

nein, das war früher so vor 0.53, nicht mehr :) https://github.com/facebook/flow/commit/20a5d7dbf484699b47008656583b57e6016cfa0b#diff -5ca8a047db3f6ee8d65a46bba4471236R29

@Hotell Ah, sicher genug! Danke, dass du mich verbessert hast.

AFAIK gibt es in TS jedoch keine Möglichkeit, den Typ der Standard-Requisiten abzuleiten. Mit dem Drei-Typ-Parameter-Ansatz wären wir wahrscheinlich in der Lage, eine korrekte Typisierung zu erhalten, ohne Upstream-Änderungen des TypeScript-Teams zu blockieren.

Kennen Sie eine Möglichkeit, den abgeleiteten Typ einer statischen Eigenschaft zu verwenden, ohne typeof MyComponent.defaultProps als Typparameter zu übergeben?

Gibt es Neuigkeiten zu diesem Thema? Führt jemand eine PR durch, um einen dritten Typparameter hinzuzufügen und https://github.com/Microsoft/TypeScript/issues/12215#issuecomment -319495340 zu verwenden?

Upvoting-Problem: gleiches Problem

+1

Ich bin auch darauf gestoßen und habe mich entschieden (bis dies ordnungsgemäß behoben ist), auf die Verwendung von static defaultProps zu verzichten und stattdessen ein Hilfs-HOC zu verwenden:

Datei components/helpers/withDefaults.tsx :

import * as React from 'react'

export interface ComponentDefaulter<DP> {
  <P extends {[key in keyof DP]?: any}>(Component: React.ComponentType<P>): React.ComponentType<
    Omit<P, keyof DP> &         // Mandate all properties in P and not in DP
    Partial<Pick<P, keyof DP>>  // Accept all properties from P that are in DP, but use type from P
  >
}

export default function withDefaults<DP>(defaultProps: DP): ComponentDefaulter<DP> {
  return Component => props => <Component {...defaultProps} {...props}/>
}

Jetzt kann ich verwenden:

Datei components/Button.tsx :

import * as React from 'react'
import withDefaults from './helpers/withDefaults'

export interface ButtonProps {
  label: string
  onPress: () => any
}

export const defaultProps = {
  onPress: () => undefined
}

class Button extends React.Component<ButtonProps> {
  // ...
}

export default withDefaults(defaultProps)(Button)

Drei mögliche Nachteile (die mir einfallen):

  1. Es erfordert ein HOC, aber da dies ein ziemlich verbreitetes Paradigma in der React-Welt ist, scheint das in Ordnung zu sein.
  2. Sie müssen die Requisiten als generische Typparameter deklarieren und können sich nicht auf Rückschlüsse aus der props -Eigenschaft verlassen.
  3. Es gibt keine implizite Überprüfung der Typen von defaultProps , aber dies kann durch die Angabe von export const defaultProps: Partial<ButtonProps> = {...} behoben werden.

Laut @vsaarinen schreibe ich eine Basisklasse mit props: Props & DefaultProps , sodass die gesamte Klasse, die die Basisklasse erweitert, this.props direkt verwenden kann, ohne this.props as PropsWithDefaults zu verwenden.

So was:

import * as React from 'react'

export class Component<P = {}, S = {}, DP = {}> extends React.Component<P, S> {
  props: Readonly<{ children?: React.ReactNode }> & Readonly<P> & Readonly<DP>
}

export interface Props {
  firstName: string
  lastName?: string
}

export interface DefaultProps {
  lastName: string
}

export class User extends Component<Props, any, DefaultProps> {
  render() {
    const { firstName, lastName } = this.props

    // no error
    return (
      <div>{firstName} {lastName.toUpperCase()}</div>
    )
  }
}

Eigentlich @qiu8310 , das funktionierte nicht vollständig, hatte immer noch Probleme mit Call-Sites, die darüber schreien, dass diese Standard-Requisiten nicht optional sind. Habe es mit einer kleinen Anpassung zum laufen bekommen

import * as React from 'react'

export class Component<P = {}, S = {}, DP = {}> extends React.Component<P, S> {
  // Cast the props as something where readonly fields are non optional
  props = this.props as Readonly<{ children?: React.ReactNode }> & Readonly<P> & Readonly<DP>
}

export interface Props {
  firstName: string
  lastName?: string
}

export interface DefaultProps {
  lastName: string
}

export class User extends Component<Props, any, DefaultProps> {
  render() {
    const { firstName, lastName } = this.props

    // no error
    return (
      <div>{firstName} {lastName.toUpperCase()}</div>
    )
  }
}

Ich spielte mit dem dritten Generikum und hatte am Ende etwas Ähnliches wie @ qiu8310 's Vorschlag:

// ComponentWithDefaultProps.ts
import * as React from "react";

export declare class ComponentWithDefaultProps<P, S, DP extends Partial<P>> extends React.Component<P & DP, S> {}
type redirected<P, S, DP> = ComponentWithDefaultProps<P, S, DP>;
const redirected: typeof ComponentWithDefaultProps = React.Component as any;

export const Component = redirected;

// User.ts
import { Component } from "ComponentWithDefaultProps";
export interface Props {
  firstName: string
  lastName?: string
}
export interface DefaultProps {
  lastName: string
}

export class User extends Component<Props, {}, DefaultProps> {
  public render() {
    const { firstName, lastName } = this.props;
    return <div>{firstName} {lastName.toUpperCase()}</div>;
  }
}

Beide Ansätze (meiner und der obige Ansatz) verursachen jedoch das größere Problem. In meinem Beispiel gibt es Arten von erstellten Komponenten:

User: React.ComponentClass<P & DP>
User["props"]: Readonly<{ children?: React.ReactNode }> & Readonly<P & DP>

Anscheinend ist die Schnittstelle User falsch. React.ComponentClass<P & DP> bedeutet, dass auch lastName benötigt wird, damit

<User firstName="" />;
//    ~~~~~~~~~~~~  Property 'lastName' is missing...

In den Beispieltypen von @qiu8310 sind die Typen unterschiedlich:

User: React.ComponentClass<P>
User["props"]: Readonly<{ children?: React.ReactNode }> & Readonly<P> & Readonly<DP>

Aber dasselbe Stück JSX verursacht denselben Fehler, da die JSX-Prüfungen von $# tsc 7$#$ auf dem Typ von props basieren .

<User firstName="John" />;
//    ~~~~~~~~~~~~~~~~  Property 'lastName' is missing...

Eine lustige Sache ist, dass <User firstName="John" /> in React.createElement(User, {firstName: "John"}) umgewandelt wird, was ein gültiges TypeScript wäre. In diesem Fall stützen sich Typprüfungen auf den ersten Typparameter von ComponentClass , also

<User firstName="Jonh" />; // doesn't work, but
React.createElement(User, { firstName: "John" }); // works

Wie Sie sehen, müssen wir trotz des dritten Generikums noch einen weiteren Trick hinzufügen, um eine Komponente mit der richtigen Schnittstelle zu exportieren:

export const User = class extends Component<Props, {}, DefaultProps> {
    // ...
} as React.ComponentClass<Props>;

<User firstName="Jonh" />; // works

Es macht also nicht viel Sinn, ein drittes Generikum zu haben.

Es scheint, dass es keine gute Lösung gibt, die mit der Definition von React zusammengeführt werden kann, denn jetzt bleibe ich bei der Verwendung ComponentWithDefaultProps und dem Festlegen des Typs der exportierten Komponente.

export interface DefaultProps {
    lastName: string;
}
export interface Props extends Partial<DefaultProps> {
    firstName: string;
}

export type PropsWithDefault = Props & DefaultProps;

export const User: as React.ComponentClass<Props> =
class extends React.Component<PropsWithDefault> {
    render() {
        // no error
        return <div>
            {this.props.firstName}
            {this.props.lastName.toUpperCase()}
        </div>;
    }
};
// Note, we've assigned `React.Component<PropsWithDefault>` to `React.ComponentClass<Props>`

Abgesehen davon können Sie jede Verwendung von this.props in den Methoden der Komponente eingeben (z. B. const { lastName } = this.props as Props & DefaultProps , oder überall mit Ausrufezeichen this.props.lastName!.toLowerCase() ).

Ich habe ein Beispiel zu dieser Diskussion gefunden - https://github.com/gcanti/typelevel-ts#objectdiff

Der sogenannte HOC-Ansatz von @rifler (ich bevorzuge Decorator) ist schon eine Weile hier , wir versuchen, eine Lösung zu finden, die keinen Laufzeitaufwand hinzufügt

Oh toll
Hoffe du findest die Lösung

irgendein Fortschritt?

Das Folgende ist eine Variation der von @r00ger erwähnten Technik:

interface IUser {
    name: string;
}
const User = class extends React.Component<IUser> {
    public static defaultProps: IUser = {name: "Foo"}
    public render() {
        return <div>{this.props.name}</div>;
    }
} as React.ComponentClass<Partial<IUser>>;
React.createElement(User, {}); // no error, will output "<div>Foo</div>"

Die Verwendung des obigen Snippets funktioniert, aber Sie verlieren die Möglichkeit, statische Eigenschaften für Benutzer zu verwenden, da es sich um eine anonyme Klasse handelt. Eine hackige Lösung wäre, den Klassennamen wie folgt zu schattieren:

// tslint:disable-next-line:no-shadowed-variable
const User = class User extends React.Component<IUser>

Sie können jetzt private statische Felder innerhalb der Klasse verwenden. Öffentliche Statiken sind immer noch unbrauchbar. Beachten Sie auch die Notwendigkeit, tslint stumm zu schalten.

Ich fand es erwähnenswert, dass ab TS 2.8 der Typ Exclude offiziell unterstützt wird:

type Omit<T, K> = Pick<T, Exclude<keyof T, K>>;

Siehe https://github.com/Microsoft/TypeScript/pull/21847.

Alles, was wir also brauchen, ist, dass React.createElement() anstelle von Props Folgendes verlangt:

Omit<Props, keyof DefaultProps>

Das einzige Problem ist, dass es in den React-Deklarationen keinen DefaultProps -Typ gibt – dafür brauchen wir entweder einen dritten Typparameter ODER die Fähigkeit, den Typ von statischen Membern als Sprachmerkmal abzuleiten.

In der Zwischenzeit haben wir Folgendes am Laufen:

/**
 * The Create type allow components to implement a strongly thed create() function
 * that alows the caller to omit props with defaults even though the component expects
 * all props to be populated. The TypeScript React typings do not natively support these.
 */
export type Create<C extends BaseComponent<any, any>, D extends {} = {}> = (
  props?: typeHelpers.ObjectDiff<C['props'], D> & React.ClassAttributes<C>,
  ...children: React.ReactNode[]
) => React.ComponentElement<any, any>;

export interface DomPropsType {
  domProps?: domProps.DomProps;
}

export class BaseComponent<P, S = {}> extends React.Component<P & DomPropsType, S> {
  static create(props?: object, ...children: React.ReactNode[]) {
    return React.createElement(this, props, ...children);
  }

  constructor(props: P & DomPropsType, context?: any) {
  ...
}

Und alle unsere Komponenten sehen so aus:

export class InsertObjectMenu extends BaseComponent<Props, State> {
  static create: Create<InsertObjectMenu, typeof InsertObjectMenu.defaultProps>;
  static defaultProps = {
    promptForImageUpload: true,
  };
  ...
}

Schließlich haben wir eine Lint-Regel, die erzwingt, dass das Attribut create für alle Komponenten deklariert wird. Wir verwenden kein JSX, also verwenden wir:

InsertObjectMenu.create({...})

Statt React.createElement() .

Wir verwenden diesen Ansatz seit fast einem Jahr mit gutem Erfolg in einer großen Codebasis, aber wir würden gerne JSX übernehmen, und das hält uns zurück.

So viel Zeit investiert in dieses "einfache Thema". Ich lasse das einfach hier https://medium.com/@martin_hotell/ultimate -react-component-patterns-with-typescript-2-8-82990c516935 🖖

    interface Component<P = {}, S = {}, DP extends Partial<P>=P> extends ComponentLifecycle<P, S> { }
    class Component<P, S, DP extends Partial<P> = P> {
        constructor(props: P & DP, context?: any);

        // We MUST keep setState() as a unified signature because it allows proper checking of the method return type.
        // See: https://github.com/DefinitelyTyped/DefinitelyTyped/issues/18365#issuecomment-351013257
        // Also, the ` | S` allows intellisense to not be dumbisense
        setState<K extends keyof S>(
            state: ((prevState: Readonly<S>, props: P) => (Pick<S, K> | S | null)) | (Pick<S, K> | S | null),
            callback?: () => void
        ): void;

        forceUpdate(callBack?: () => void): void;
        render(): ReactNode;

        // React.Props<T> is now deprecated, which means that the `children`
        // property is not available on `P` by default, even though you can
        // always pass children as variadic arguments to `createElement`.
        // In the future, if we can define its call signature conditionally
        // on the existence of `children` in `P`, then we should  remove this.
        private __externalProps: Readonly<{ children?: ReactNode }> & Readonly<P>;
        props: Readonly<{ children?: ReactNode }> & Readonly<P> & DP;
        state: Readonly<S>;
        context: any;
        refs: {
            [key: string]: ReactInstance
        };
    }

    class PureComponent<P = {}, S = {}, DP extends Partial<P>=P> extends Component<P, S, P> { }


interface ElementAttributesProperty { __externalProps: {}; }

Schauen Sie sich die letzte Zeile genau an.

Mit diesen Änderungen könnten wir haben

interface Props {
    a: string
    b?: string
    c?: string
}

class Comp extends React.Component<Props, {}, typeof Comp.defaultProps> {
    static defaultProps = {
        b: ''
    }

    render() {
        const {a, b, c} = this.props

        let res = a.concat(b)  // ok
        let res1 = a.concat(c) //fail

        return null
    }
}



const res1= <Comp a=''/> // ok
const res3 = <Comp /> // fail

Was wir am besten erreichen können, wenn wir static defaultProps verwenden (ts checker sollte geändert werden, wenn wir typeof Comp.defaultProps weglassen wollen).
Andere Optionen, wurde bereits gesagt - HOC, Type Casts.

Hier ist mein (sehr hässlicher) Versuch basierend auf der Idee von https://medium.com/@martin_hotell/ultimate -react-component-patterns-with-typescript-2-8-82990c516935:

type ExtractProps<T> = T extends React.ComponentType<infer Q> ? Q : never;
type ExtractDefaultProps<T> = T extends { defaultProps?: infer Q } ? Q : never;
type RequiredProps<P, DP> = Pick<P, Exclude<keyof P, keyof DP>>;
type RequiredAndPartialDefaultProps<RP, DP> = Required<RP> & Partial<DP>;

type ComponentTypeWithDefaultProps<T> =
  React.ComponentType<
    RequiredAndPartialDefaultProps<
      RequiredProps<ExtractProps<T>, ExtractDefaultProps<T>>,
      ExtractDefaultProps<T>
    >
  >;

function withDefaultProps<T extends React.ComponentType<any>>(Comp: T) {
  return Comp as ComponentTypeWithDefaultProps<T>;
}
interface IProps {
  required: number;
  defaulted: number;
}

class Foo extends React.Component<IProps> {
  public static defaultProps = {
    defaulted: 0,
  };
}

// Whichever way you prefer... The former does not require a function call
const FooWithDefaultProps = Foo as ComponentTypeWithDefaultProps<typeof Foo>;
const FooWithDefaultProps = withDefaultProps(Foo);

const f1 = <FooWithDefaultProps />;  // error: missing 'required' prop
const f2 = <FooWithDefaultProps defaulted={0} />;  // error: missing 'required' prop
const f3 = <FooWithDefaultProps required={0} />;  // ok
const f4 = <FooWithDefaultProps required={0} defaulted={0} />;  // ok

@decademoon , es scheint, als könnten wir diese Lösung einfach bei @types/react verwenden, oder? Ich meine, wenn wir das übliche React.ComponentType durch Ihre Lösung ersetzen.
Wenn ja, können Sie vielleicht eine PR erstellen?

@decademoon Ihre Definition behandelt nicht den Fall, in dem die nicht standardmäßigen Requisiten tatsächlich optionale Felder enthalten, dh

interface IProps {
  required: number;
  notRequired?: () => void;
  defaulted: number;
}

class Foo extends React.Component<IProps> {
  public static defaultProps = {
    defaulted: 0,
  };
}

Ich habe es in meinem Fall zum Laufen gebracht, indem ich den Typ "RequiredAndPartialDefaultProps" so geändert habe, dass "RP" nicht mit "Required" umschlossen wird.

type RequiredAndPartialDefaultProps<RP, DP> = RP & Partial<DP>;

Ich bin überrascht, dass es immer noch keine richtige Lösung oder zumindest ein funktionierendes HOC für NPM gibt. es sei denn, ich habe etwas übersehen.

Hallo allerseits. Ich wollte nur sagen und falls Sie diesen Thread noch lesen: Ich denke, @JoshuaToenyes hat die sinnvollste und hilfreichste Erklärung abgegeben. Dies ist definitiv kein Problem, also hat es nichts damit zu tun. Verwenden Sie in diesem Fall die Typzusicherung.

@toiletpatrol Tatsächlich verarbeitet die Lösung von @decademoon (mit meiner geringfügigen Änderung) automatisch Standard-Requisiten ganz gut. Es könnte definitiv in die DT-Definitionen für React integriert werden, um den Feature-Standard für alle bereitzustellen.

@toiletpatrol @RobRendell hast du es gesehen https://github.com/Microsoft/TypeScript/issues/23812?

@vkrol Das habe ich gesehen, aber ich kann die Implementierung von Dekademoon jetzt in meiner Codebasis löschen, ohne auf die Veröffentlichung neuer Funktionen zu warten.

Eine andere Problemumgehung, die ich jetzt für knifflige Fälle verwende:

const restWithDefaults = { ...Component.defaultProps, ...rest };
return <Component {...restWithDefaults} />;

Ich denke, daran ist nichts auszusetzen, also lasse ich es hier als schmutzigen, aber einfachen Workaround.

TS 3.2 und React 16.7-Typisierungen beheben dies. können wir schließen?

@Hotell wie soll es letztendlich gehandhabt werden? Ich bekomme das immer noch nicht richtig zum Laufen

Um anderen Zeit zu sparen, hier ein Link zu den Release Notes von Typescript 3:
Unterstützung für defaultProps in JSX

@cbergmiller Ich fürchte, das sind die Versionshinweise für TypeScript 3.1 🙃

Ich habe immer noch das gleiche Problem mit React.FunctionComponent

@denieler Ich würde nicht raten, defaultProps mit React.FunctionComponent zu verwenden, es ist nicht natürlich. Es ist besser, Standardfunktionsparameter zu verwenden:

interface HelloProps {
  name?: string;
  surname?: string;
}

const HelloComponent: React.FunctionComponent<HelloProps> = ({
  name = 'John',
  surname = 'Smith',
}) => {
  return <div>Hello, {name} {surname}!</div>
};

@mgol Wie würden Sie Standardfunktionsparameter definieren, wenn ich die Requisiten nicht destrukturieren wollte?
Ich kann nur daran denken, nur die "standardmäßigen" Eigenschaften wie folgt zu destrukturieren:

interface HelloProps {
  name?: string;
  surname?: string;
}

const HelloComponent: React.FunctionComponent<HelloProps> = ({
  name = 'John',
  surname = 'Smith',
  ...props
}) => {
  return <div>Hello, {name} {surname}! You are {props.age} years old.</div>
};

Aber ich finde es beschämend, nur einige der Requisiten zu extrahieren.

@glecetre Sie können verwenden:

HelloComponent.defaultProps = {
    name: 'John',
    surname: 'Smith'
}

@Glinkis bitte beachten Sie https://github.com/reactjs/rfcs/pull/107/files#diff -20b9b769068a185d90c23b58a2095a9dR184.

@glecetre Warum willst du nicht alle Requisiten destrukturieren? Es ist einfacher als defaultProps zu definieren und einfacher einzugeben. Der Requisitentyp der klassenbasierten Komponente kann Sie beißen, wenn Sie exportieren, um ihn extern zu verwenden, da erforderliche Requisiten möglicherweise nicht mehr erforderlich sind, wenn es einen Eintrag für sie in defaultProps gibt. Die Verwendung defaultProps scheint auch ein wenig magisch zu sein, während bei der Parameterdestrukturierung alles JavaScript ist.

War diese Seite hilfreich?
0 / 5 - 0 Bewertungen