Problem
次の関数changeValueByKeyようにObjectのkeyによってvalueを変更する関数を型安全に作りたい!
type State = {
text: string;
isActive: boolean;
};
let state: State = {
text: "",
isActive: false
}
const changeText = (value: string) => {
// OK
state['text'] = value;
}
const changeIsActive = (value: boolean) => {
// OK
state['isActive'] = value;
}
const changeValueByKey = (key: 'text' | 'isActive', value: string | boolean) => {
// Type Error
state[key] = value;
}
Solution
- こちらのStack Overflowを参考にしました
type State = {
text: string;
isActive: boolean;
};
let state: State = {
text: "",
isActive: false
}
const changeValueByKey = <K extends keyof State>(key: K, value: State[K]) => {
state[key] = value;
}
// OK
changeValueByKey('text', 'test')
changeValueByKey('isActive', true)
// Type Error
changeValueByKey('text', true)
changeValueByKey('isActive', 'test')
- 解説
-
keyofを使うことでプロパティ名のtypeを参照することができます -
keyof StateでStateのプロパティ名を参照し、それをextends継承したtypeKをGenericsとして用意します - 第一引数
keyはプロパティ名なのでそのままKを使用し、第二引数valueはStateのプロパティKのvalueの型なのでState[K]とします - これでkeyは
text | isActiveとなり、keyを指定した時にvalueの型が決まるようになります - keyに
textを指定した時にvalueはState['text']なのでstringに、isActiveを指定した時にvalueはState['isActive']なのでbooleanしか渡せないようになりました
-
- 今すぐ動作を確認してみたい方はこちら
TypeScriptに対応したEditorならサジェストも出ます

Demo
- Reactの
useStateにObjectを入れて実際に使ってみた時のサンプルはこちら
See the Pen Demo: change object value type by key by mikan3rd (@mikan3rd) on CodePen.
↑ Code SandboxはQiitaに埋め込みできないようなのでCodePenを埋め込んであります
(ただしCodePenではType Errorなどは出ません・・・)