Definitelytyped: Einige bestehende Verbindungsanrufe werden von 5.0.16 unterbrochen

Erstellt am 11. Apr. 2018  ·  3Kommentare  ·  Quelle: DefinitelyTyped/DefinitelyTyped

  • [x] Ich habe versucht, das Paket @types/xxxx und hatte Probleme.
  • [x] Ich habe versucht, die neueste stabile Version von tsc zu verwenden. https://www.npmjs.com/package/typescript
  • [x] Ich habe eine Frage, die für StackOverflow unangemessen ist. (Bitte stellen Sie dort entsprechende Fragen).
  • [x] [Erwähnen](https://github.com/blog/821-mention-somebody-they-re-notified) die Autoren (siehe Definitions by: in index.d.ts ), damit sie es können Antworten.

    • Autoren: @Pajn @tkqubo @thasner @kenzierocks @clayne11 @tansongyang @NicholasBoll @mDibyo @pdeva

Die Probleme)

Hallo! Ich habe gerade auf 5.0.16 aktualisiert und bin sofort auf einige Probleme bei der Verwendung dieser neuen Eingaben in meinem bestehenden Projekt gestoßen. Hier sind einige relevante Versionsnummern:

@types/react-redux: ^5.0.16,
typescript: ^2.8.x,
react-redux: ^5.0.5,

Ein typischer Container wird nicht kompiliert

Hier ist ein Code, der meiner Meinung nach kompiliert werden sollte (und der vor 5.0.16 kompiliert wurde und der erneut kompiliert wird, wenn wir die Version auf 5.0.15 ):

// components/exampleComponent.ts
import React = require('react')
import { IState, IDateRange, ReportType } from '../../types/index'

export interface IExampleProps {
  label?: string
  dateRange: IDateRange
  onDateRangeChange: (value: IDateRange) => void
}

export class ExampleComponent extends React.Component<IExampleProps> {
  // implementation
}
// containers/exampleComponent.ts
import { connect } from 'react-redux'
import { IState, IDateRange, ReportType } from '../../types/index'

interface IPropsFromState {
  dateRange: IDateRange
}

interface IPropsFromParent {
  reportType: ReportType
}

const mapStateToProps = (state: IState, props: IPropsFromParent): IPropsFromState => {
  const config = state.reporting.reportConfigs[props.reportType]

  return {
    dateRange: config ? config.dateRange : null,
  }
}

const connector = connect<IPropsFromState, null, IPropsFromParent>(
  mapStateToProps,
)

export const ExampleContainer = connector(ExampleComponent) // <-- this does not compile

Normalerweise würde ich den Container so verwenden,

<ExampleContainer reportType={ReportType.USERS_CREATED} />

Mit diesem Code erhalte ich jedoch unter Verwendung des neuesten @types/react-redux bei 5.0.16 und Typoskript bei 2.8.1 stattdessen die folgende Fehlermeldung:

[ts]
Argument of type 'typeof ExampleComponent' is not assignable to parameter of type 'ComponentType<IPropsFromState & DispatchProp<any> & IPropsFromParent>'.
  Type 'typeof ExampleComponent' is not assignable to type 'StatelessComponent<IPropsFromState & DispatchProp<any> & IPropsFromParent>'.
    Type 'typeof ExampleComponent' provides no match for the signature '(props: IPropsFromState & DispatchProp<any> & IPropsFromParent & { children?: ReactNode; }, context?: any): ReactElement<any>'.

Wenn man sich die Änderungen ansieht, die in 5.0.16 , fühlt es sich an, als ob das Typsystem gestört ist, da connector den Typ InferableComponentEnhancerWithProps<IPropsFromState & IPropsFromParent, IPropsFromParent> was bedeutet, dass es erwartet, dass das erste Argument vom Typ IPropsFromState & IPropsFromParent . Meiner Basiskomponente fehlt die Eigenschaft reportType .

Wenn ich zum Beispiel das schreibe:

const f = <P extends IPropsFromParent & IPropsFromState>(component: Component<P>) => { /**/ }
const g = <P extends IPropsFromParent & IPropsFromState>(props: P) => { /**/ }

const record: IExampleProps = null

f(ExampleComponent)
g(record)

Diese Minimalbeispiele scheitern. Der erste schlägt aus dem gleichen Grund wie der obige Code fehl, mit der gleichen undurchsichtigen Fehlermeldung. Die zweite schlägt fehl, weil IExampleProps offensichtlich keine Eigenschaft reportType: ReportType also können wir IExampleProps P zuweisen. Es fehlt reportType . Ich vermute, dass dies unter der Haube dazu führt, dass das erste Beispiel fehlschlägt.

Es sieht so aus, als ob Container nach 5.0.16 keine neuen Eigenschaften zu den Schnittstellen ihrer umschlossenen Komponenten hinzufügen dürfen? Das sehe ich, wenn ich mir den Code ansehe.

Es gehört zu meinem normalen Arbeitsablauf, Komponenten nur hinsichtlich der benötigten Eigenschaften zu definieren und diese Komponenten dann mit HOCs zu erweitern, die eine neue Schnittstelle definieren und der Komponente ihre Eigenschaften über den Redux Store bereitstellen. In einigen Fällen ist die neue Schnittstelle eine Teilmenge der Schnittstelle der umschlossenen Komponente, in anderen Fällen jedoch nicht. Im obigen Fall hat die neue Schnittstelle eine zusätzliche Eigenschaft reportType die der Aufrufer verwendet, die aber die umschlossene Komponente nie sehen wird.


Ein eigenwilligerer Container wird nicht kompiliert

Ich habe ein weiteres Beispiel für eine Technik, die ich verwende, die durch diese Änderung unterbrochen wird:

Angenommen, wir haben zwei einfache Komponenten,

class NameDateComponent extends React.PureComponent<{ name: string, date: string}> {}

class DateOnlyComponent extends React.PureComponent<{ date: string }> {}

Ich möchte ein HOC erstellen, das die date für diese Komponenten bereitstellt, ohne überhaupt etwas über die Eigenschaft name wissen zu müssen. Auf diese Weise kann ich zum Beispiel einen NameProvider und einen DateProvider erstellen und sie so zusammensetzen: NameProvider(DateProvider(BaseComponent)) oder so DateProvider(NameProvider(BaseComponent)) , was ich normalerweise mit einer gut typisierten Komponente nicht tun kann Enhancer, da TOwnProps .

interface IWithDate {
  date: string
}

// ComponenProps defines a component interface that includes IWithDate
// NewAPI defines a new interface that excludes IWithDate
// so the types represent only what will change in the given component, without needing to know the rest of the interface
function DateProvider <ComponentProps extends IWithDate, NewAPI extends Minus<ComponentProps, IWithDate>> (Base: CompositeComponent<ComponentProps>) {

  const enhancer = connect<ComponentProps, null, NewAPI>(
    (_state: IState, props: NewAPI): ComponentProps => {
      // because of the 'never' type, 
      // typescript doesn't think NewAPI & IWithProps == ComponentProps
      // so we have to coerce this (but you and I can see that the above holds)
      const newProps: any = Object.assign({
        date: '2017-01-01'
      }, props)

      return newProps as ComponentProps
    },
    null
  )

  return enhancer(Base) // <-- after 5.0.16 this line does not compile
}

Dieser neue schnittstellenunabhängige Komponenten-Enhancer wird wie folgt verwendet:

const NameOnly = DateProvider(NameDateComponent)
const Nothing = DateProvider(DateOnlyComponent)

.
.
.

<Nothing />
<NameOnly name='Bob' />
<NameDateComponent name='Bob' date='2017-01-01' />

Der DateProvider HOC ist also in der Lage, eine Komponente zu erweitern, ohne sich der Schnittstelle dieser Komponente vollständig bewusst zu sein. Es muss nur wissen, dass die angegebene Komponente in der Lage ist, die von ihr bereitgestellten Requisiten zu akzeptieren.

Mit 5.0.16 funktioniert das nicht mehr, stattdessen bekomme ich folgende Fehlermeldung:

[ts]
Argument of type 'CompositeComponent<ComponentProps>' is not assignable to parameter of type 'ComponentType<ComponentProps & NewAPI>'.
  Type 'ComponentClass<ComponentProps>' is not assignable to type 'ComponentType<ComponentProps & NewAPI>'.
    Type 'ComponentClass<ComponentProps>' is not assignable to type 'StatelessComponent<ComponentProps & NewAPI>'.
      Types of property 'propTypes' are incompatible.
        Type 'ValidationMap<ComponentProps>' is not assignable to type 'ValidationMap<ComponentProps & NewAPI>'.
          Type 'keyof ComponentProps | keyof NewAPI' is not assignable to type 'keyof ComponentProps'.
            Type 'keyof NewAPI' is not assignable to type 'keyof ComponentProps'.
              Type 'keyof NewAPI' is not assignable to type '"date"'.

Beim Herumspielen ist mir folgendes aufgefallen:

interface IWithDate {
  date: string
}

interface IComponentProps {
  name: string
  date: string
}

// I've torn out the internals of the DateProvider above
const connect1 = <T extends IWithDate, U extends Omit<T, keyof IWithDate>>(base: CompositeComponent<T>) => {
  const enhancer: InferableComponentEnhancerWithProps<T & U, U> = () => null

  return enhancer(base) // <-- this is a compile error
}

const connect2 = <T extends IWithDate, U extends Omit<T, keyof IWithDate>>() => {
  const enhancer: InferableComponentEnhancerWithProps<T & U, U> = () => null

  return enhancer
}

const enhancer = connect2<IComponentProps, Omit<IComponentProps, keyof IWithDate>>()
const container = enhancer(NameDateComponent) // <-- this is not a compile error

Wenn wir den Connector explizit eingeben, funktioniert alles?


Das ist es! Danke fürs Lesen ;) Im Moment habe ich mein @types/react-redux auf eine frühere Version gesetzt und alles ist gut.

Hilfreichster Kommentar

Das Zurücksetzen auf 5.0.15 behebt das Problem nicht vollständig . Während 5.0.15 diese Art von Code ohne Warnung kompilieren wird, treten dennoch Fehler auf, wenn Sie eine Typprüfung der Requisiten für die Präsentationskomponente im connect Aufruf hinzufügen. (Angenommen, Ihre Wrapping-Komponente hat eine Requisite, die MyComponent nicht hat)

Dies funktioniert zum Beispiel in 5.0.15, aber nicht in 5.0.16
connect(stateToProps, dispatchToProps)(MyComponent)

Aber selbst in 5.0.15 können Sie die MyComponent Requisiten nicht ohne Compilerfehler überprüfen
connect<statetoprops, dispatchtoprops, mycomponentprops)(stateToProps, dispatchToProps)(MyComponent)
Dies führt zu einem Fehler, wenn Sie sich beschweren, dass die Umhüllungskomponenten-Requisite in MyComponent nicht vorhanden ist

Ich denke, dies ist ein größeres Problem, das in den Typzuordnungen lauert, die die Bereinigung von

Alle 3 Kommentare

@verschiedeneAutoren könnten Sie bitte die Versionen von @types/react und @types/react-redux teilen, die Sie verwenden?

EDIT: die @ die Dinge durcheinander gebracht und die Namen der Libs sind nicht erschienen, sorry: enttäuscht:

@verschiedeneAutoren Ich denke, du genau richtig

Es scheint, als ob Container nach 5.0.16 keine neuen Eigenschaften zu den Schnittstellen ihrer umhüllten Komponenten hinzufügen dürfen? Das sehe ich, wenn ich mir den Code ansehe.

Der Fehler besteht darin, dass die Typdefinitionen für die Funktion connect Redux ownProps und mapPropsToState überschneiden . Dies bedeutet, dass jede "Container"-Komponente gezwungen ist, ihre Requisiten in alle abgeleiteten "Präsentations"-Komponenten zu replizieren - was gängige Redux-Entwurfsmuster durchbricht.

PR, die eingeführt wurde: https://github.com/DefinitelyTyped/DefinitelyTyped/pull/24764
Anderes Problem: https://github.com/DefinitelyTyped/DefinitelyTyped/issues/24922

Das Zurücksetzen auf 5.0.15 behebt das Problem nicht vollständig . Während 5.0.15 diese Art von Code ohne Warnung kompilieren wird, treten dennoch Fehler auf, wenn Sie eine Typprüfung der Requisiten für die Präsentationskomponente im connect Aufruf hinzufügen. (Angenommen, Ihre Wrapping-Komponente hat eine Requisite, die MyComponent nicht hat)

Dies funktioniert zum Beispiel in 5.0.15, aber nicht in 5.0.16
connect(stateToProps, dispatchToProps)(MyComponent)

Aber selbst in 5.0.15 können Sie die MyComponent Requisiten nicht ohne Compilerfehler überprüfen
connect<statetoprops, dispatchtoprops, mycomponentprops)(stateToProps, dispatchToProps)(MyComponent)
Dies führt zu einem Fehler, wenn Sie sich beschweren, dass die Umhüllungskomponenten-Requisite in MyComponent nicht vorhanden ist

Ich denke, dies ist ein größeres Problem, das in den Typzuordnungen lauert, die die Bereinigung von

War diese Seite hilfreich?
0 / 5 - 0 Bewertungen