絶対に忘れるのでメモ。
2022-04-18追記
知識浅すぎて悲しくなりました。
Partial
というそれ用の型宣言方法がありました。
内部でやってることはこの記事と似てる。
やりたいこと
変数宣言時にオブジェクト型を代入すると勝手にその値のkey
を持った型として定義される。
そのオブジェクト型変数のキーをオプショナルにした上で他の変数の型として使いたい。
単純にその型を書けばいいんだけど面倒なので書きたくない。
新しく追加するたびに型の部分も値の部分も直さなきゃだし。
const ErrorMessages: {
// ここを書きたくない
logInFaild?: string;
invalidValue?: string;
} = {
logInFaild: 'ユーザー名かパスワードが間違っています。',
invalidValue: '数値で入力してください。',
}
const messages: typeof ErrorMessages = {}
結論
ここまでの内容で察せられる人用。
const ErrorMessages = {
logInFaild: 'ユーザー名かパスワードが間違っています。',
invalidValue: '数値で入力してください。',
}
type keys = keyof typeof ErrorMessages
type ErrorMessageType = {[key in keys]?: string }
const messages: ErrorMessageType = {}
// ↓定義される型
type ErrorMessageType = {
logInFaild?: string | undefined
invalidValue?: string | undefined
}
詳しく
オブジェクト型(辞書型)を変数に入れると型推論によって勝手に型が決まる。
例としてはこんなシチュエーション。
表示するメッセージの一覧的な定数(=メッセージ辞書)を作る。
実際にメッセージを入れておく変数には、メッセージ辞書のキーと値を入れる。
メッセージ変数のキーはメッセージ辞書に存在するもののみに制限したい。
そのメッセージが不要な時は値を入れたくないのでオプショナルにもしたい。
コードにするとこう↓
const ErrorMessages = {
logInFailed: 'ユーザー名かパスワードが間違っています。',
invalidValue: '数値で入力してください。',
}
const messages = {}
if (login()) {
// ログイン成功
} else {
// ログイン失敗
messages.logInFailed = ErrorMessages.logInFailed // エラー
}
このままだとmessages
には{}
型、つまり「キーを持たないオブジェクト型」が定義されているのでエラー
部分でエラーになる。
Property 'logInFailed' does not exist on type '{}'
解決方法(結論部分の説明)
typeof
、keyof
、in
、Mapped Types
を組み合わせて解決する。
まずtypeof
とkeyof
で「メッセージ辞書のキーのみを入れられるstring型」を作る。
const ErrorMessages = {
logInFaild: 'ユーザー名かパスワードが間違っています。',
invalidValue: '数値で入力してください。',
}
type keys = keyof typeof ErrorMessages
// 実際に作成される型
// type keys = "logInFaild" | "invalidValue"
Mapped Typesでキーを制限したオブジェクト型を作るが、その時に?
を付けてオプショナルにする。
type ErrorMessageType = {
[key in keys]?: string // `key`には'logInFaild'と'invalidValue'しか入れられない
}
これでメッセージ変数を宣言すればキーがオプショナルなオブジェクト型ができる。
const messages: ErrorMessageType = {}