オブジェクトが入ったuseStateを更新したい
次のような型定義のオブジェクトがあったとする
type UserProfile = {
name: string;
email: string;
age: number;
};
const [profile, setProfile] = useState<UserProfile>({
name: '',
email: '',
age: 0,
});
更新関数を愚直に書いていく
これでも動きはしますが重複コードが多いです。フィールドが増えるたびに関数が増えていくのでメンテナンスも面倒くさそう。
// name用
const handleNameChange = (e: React.ChangeEvent<HTMLInputElement>) => {
setProfile((prev) => ({ ...prev, name: e.target.value }));
};
// email用
const handleEmailChange = (e: React.ChangeEvent<HTMLInputElement>) => {
setProfile((prev) => ({ ...prev, email: e.target.value }));
};
// age用
const handleAgeChange = (e: React.ChangeEvent<HTMLInputElement>) => {
setProfile((prev) => ({ ...prev, age: Number(e.target.value) }));
};
共通の更新関数にまとめる
オブジェクト内のプロパティ名やプロパティの値の型が変更されたとしても、関数に変更は加えなくて良い保守性の高い関数になりました
const handleProfileChange = <K extends keyof UserProfile>(
field: K,
value: UserProfile[K],
) => {
setBlackboard((prev) => ({
...prev,
[field]: value,
}));
};
// 使用例
<input
type="text"
value={profile.name}
onChange={(e) => handleProfileChange('name', e.target.value)}
/>
解説
-
extends keyof T
でオブジェクトのプロパティを型にしている。それにextends
で部分型制約をつけている - 型引数を使っているので、関数を使用するときに型を指定してやる必要がある。その指定する型に制約がついている
- 制約というのは、
UserProfile
オブジェクトのプロパティ名のいずれかでなければならないというもの - オブジェクトのプロパティの型を取得することで、valueの型を定義することができる
参考