J'utilise TypeScript avec React pour un projet. Le composant principal est transmis à l'état avec cette interface.
interface MainState {
todos: Todo[];
hungry: Boolean;
editorState: EditorState; //this is from Facebook's draft js
}
Cependant, le code ci-dessous (seulement un extrait) ne sera pas compilé.
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
});
}
}
Le compilateur se plaint du fait que, dans la méthode onChange
où je ne tente de définir que l'état d'une propriété, la propriété todos
et la propriété hungry
sont manquantes dans le type { editorState: EditorState;}
. En d'autres termes, je dois définir l'état des trois propriétés dans la fonction onChange
pour que le code soit compilé. Pour compiler, je dois faire
onChange(editorState: EditorState){
this.setState({
todos: [],
hungry: false,
editorState: editorState
});
}
mais il n'y a aucune raison de définir les propriétés todos
et hungry
à ce stade du code. Quelle est la bonne façon d'appeler setState sur une seule propriété dans TypeScript/react?
Les définitions de react ont été mises à jour et la signature de setState
est maintenant:
setState<K extends keyof S>(state: Pick<S, K>, callback?: () => any): void;
Où Pick<S, K>
est un type intégré qui a été ajouté dans TypeScript 2.1:
type Pick<T, K extends keyof T> = {
[P in K]: T[P];
}
Voir Types mappés pour plus d'informations.
Si vous rencontrez toujours cette erreur, vous pouvez envisager de mettre à jour vos définitions de réaction.
Je suis confronté à la même chose.
Les deux manières dont je parviens à contourner ce problème agaçant sont les suivantes:
(1) casting/assertion:
this.setState({
editorState: editorState
} as MainState);
(2) déclarer les champs d'interface comme optionnels:
interface MainState {
todos?: Todo[];
hungry?: Boolean;
editorState?: EditorState;
}
Si quelqu'un a une meilleure solution, je serais heureux de le savoir!
Bien que cela reste un problème, deux discussions sont en cours sur les nouvelles fonctionnalités qui résoudront ce problème:
Types partiels (propriétés facultatives pour les types existants)
et
typage plus précis de Object.assign et React composant setState ()
Etat de mise à jour explicite, exemple avec le compteur
this.setState((current) => ({ ...current, counter: current.counter + 1 }))
Je pense que la meilleure façon de le faire est d'utiliser Partial
Déclarez votre composant de la manière suivante
class Main extends React.Component<MainProps, Partial<MainState>> {
}
Partial modifie automatiquement toutes les clés en option.
Edit: NE PAS UTILISER cette solution, préférez https://stackoverflow.com/a/41828633/1420794 Voir les commentaires pour plus de détails.
Maintenant que cet opérateur de spread a été expédié dans TS, ma solution préférée est
this.setState({...this.state, editorState}); // do not use !
On peut dire à setState
à quel champ il devrait s’attendre, en le paramétrant avec <'editorState'>
:
this.setState<'editorState'>({
editorState: editorState
});
Si vous mettez à jour plusieurs champs, vous pouvez les spécifier comme ceci:
this.setState<'editorState' | 'hungry'>({
editorState: editorState,
hungry: true,
});
bien que cela vous permette de ne spécifier qu’un seul d’entre eux!
Quoi qu'il en soit avec le dernier TS et @types/react
Les deux options ci-dessus sont facultatives, mais elles nous amènent à ...
Si vous souhaitez utiliser une clé dynamique , vous pouvez indiquer à setState
de ne pas attendre de champs en particulier:
this.setState<never>({
[key]: value,
});
et comme mentionné ci-dessus, il ne se plaint pas si nous passons un champ supplémentaire.
( numéro de GitHub )