@types/xxxx
und hatte Probleme.Definitions by:
in index.d.ts
), damit sie es können Antworten.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,
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.
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.
@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
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, dieMyComponent
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üfenconnect<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 istIch denke, dies ist ein größeres Problem, das in den Typzuordnungen lauert, die die Bereinigung von