Ik gebruik Typescript met React voor een project. De hoofdcomponent krijgt een status met deze interface.
interface MainState {
todos: Todo[];
hungry: Boolean;
editorState: EditorState; //this is from Facebook's draft js
}
De onderstaande code (alleen een uittreksel) kan echter niet worden gecompileerd.
class Main extends React.Component<MainProps, MainState> {
constructor(props) {
super(props);
this.state = { todos: [], hungry: true, editorState: EditorState.createEmpty() };
}
onChange(editorState: EditorState) {
this.setState({
editorState: editorState
});
}
}
De compiler klaagt dat, in de onChange
-methode, waarbij ik alleen State probeer in te stellen voor één eigenschap, de eigenschap todos
en de eigenschap hungry
ontbreekt in type { editorState: EditorState;}
. Met andere woorden, ik moet de status van alle drie de eigenschappen in de functie onChange
instellen om de code te laten compileren. Om het te compileren, moet ik doen
onChange(editorState: EditorState){
this.setState({
todos: [],
hungry: false,
editorState: editorState
});
}
maar er is geen reden om de eigenschap todos
en de eigenschap hungry
op dit punt in de code in te stellen. Wat is de juiste manier om setState op slechts één eigenschap aan te roepen in typoscript/react?
Antwoord 1, autoriteit 100%
Bewerken
De definities voor reageren zijn bijgewerkt en de handtekening voor setState
is nu:
setState<K extends keyof S>(state: Pick<S, K>, callback?: () => any): void;
Waar Pick<S, K>
een ingebouwd type is dat is toegevoegd in Typescript 2.1:
type Pick<T, K extends keyof T> = {
[P in K]: T[P];
}
Zie Toegewezen typenvoor meer informatie.< br>
Als je deze fout nog steeds hebt, kun je overwegen om je reactiedefinities bij te werken.
Oorspronkelijke antwoord:
Ik zit met hetzelfde.
De twee manieren waarop ik dit vervelende probleem kan omzeilen zijn:
(1) casting/bewering:
this.setState({
editorState: editorState
} as MainState);
(2) de interfacevelden als optioneel declareren:
interface MainState {
todos?: Todo[];
hungry?: Boolean;
editorState?: EditorState;
}
Als iemand een betere oplossing heeft, hoor ik het graag!
Bewerken
Hoewel dit nog steeds een probleem is, zijn er twee discussies over nieuwe functies die dit probleem zullen oplossen:
Gedeeltelijke typen (optionele eigenschappen voor bestaande typen)
en
Nauwkeuriger typen van Object.assign en React component setState()
Antwoord 2, autoriteit 36%
Status expliciet bijwerken, voorbeeld met de teller
this.setState((current) => ({ ...current, counter: current.counter + 1 }))
Antwoord 3, autoriteit 14%
Ik denk dat de beste manier om dit te doen is om Partial
. te gebruiken
Declareer uw component op de volgende manier
class Main extends React.Component<MainProps, Partial<MainState>> {
}
Gedeeltelijk verandert automatisch alle toetsen in optioneel.
Antwoord 4, autoriteit 5%
We kunnen setState
vertellen welk veld het moet verwachten, door het te parametreren met <'editorState'>
:
this.setState<'editorState'>({
editorState: editorState
});
Als u meerdere velden bijwerkt, kunt u deze als volgt specificeren:
this.setState<'editorState' | 'hungry'>({
editorState: editorState,
hungry: true,
});
hoewel je er eigenlijk mee wegkomt door er maar één te specificeren!
Hoe dan ook, met de nieuwste TS en @types/react
zijn beide bovenstaande optioneel, maar ze leiden ons naar…
Als u een dynamische sleutelwilt gebruiken, kunnen we setState
laten weten dat er geen velden in het bijzonder worden verwacht:
this.setState<never>({
[key]: value,
});
en zoals hierboven vermeld, klaagt het niet als we een extra veld doorgeven.
Antwoord 5, autoriteit 2%
Bewerken: GEBRUIK deze oplossing NIET, liever https://stackoverflow.com/a/41828633/1420794
Zie opmerkingen voor details.
Nu de spread-operator in TS is verzonden, is mijn voorkeursoplossing
this.setState({...this.state, editorState}); // do not use !
Antwoord 6, autoriteit 2%
Ik hou niet van casten en tijdelijke oplossingen die je veel ruimte geven om fouten te maken terwijl je je project opschaalt. Hier is mijn oplossing.
- We moeten de juiste intellisense voor de sleutel krijgen door een generiek type te gebruiken
<K extends keyof MainState>
- Vervolgens moeten we het juiste type voor waarde krijgen op basis van de ingevoerde sleutel
typeof MainState[K]
-
Om code te krijgen zonder en een fout en zonder casting/workarounds enz. te gebruiken, geef je callback door aan
this.setState
-
Allemaal combineren
onChange = <K extends keyof MainState>(fieldName: K, value: typeof MainState[K]) => {
this.setState((prevState) => {
return {
...prevState,
[fieldName]: value,
};
});
};