なにを言ってるんだァおめー?と思っている人が居たらそれは正しくて、あたしもこのタイトルを書いておいて(コンテキスト0だとあたりまえ体操だな)となっているワケですわね。
例題
2つの等しい value を持つ object が存在するとして、共通の value のみ残した object を作りたいと思う
const values = {
hoge: 'fuga',
moge: 'piyo',
} as const;
const searchTarget = {
hoge: 'fuga',
moge: 'boeeeee',
};
// values と searchTarget で共通の value を持つキーのみ残したものを作りたい
// const newValue = { hoge: 'fuga' }; // のような
このとき Object#fromEntries と Object#entries を使って以下のような実装をすると思う
Object.fromEntries(
Object.entries(searchTarget).filter(
([_, text]) => Object.values(values).includes(text)
)
)
js のコンテキストとしては問題ない、がTS のコンテキストだとエラーになる
なにが問題?
エラー出力の内容の通りなのだが Object.values
で引っ張ってきた配列の型が 'fuga' | 'piyo'
になっていて Object.entries(searchTarget)
で引っ張ってくる text
が string
のため適合しないと言われる
解法
1. toString()
を経由した string
へのダウンキャスト
社で教えてもらった方法。 String#toString
を 利用( 悪用 ) しつつ Array#some
で検索するようにする
Object.fromEntries(
Object.entries(searchTarget).filter(
([_, text]) => Object.values(values)
.some((value) => value.toString() === text) // value の定義は 'fuga' | 'piyo'
)
)
Array の存在確認系の実装は脳死で includes()
使いがちだったのだが some()
を使えば中でごにょごにょできる。
その上で value に対して toString
を使う。すると型定義が string
にダウンキャストされる
これによって型が適合する
2. Object.values
に対してジェネリクスで string
を渡す
身内の Discord のメンバーの人に教えてもらった方法。こちらはタイトルと関係ないがスマートなのでご紹介。
Object.fromEntries(
Object.entries(searchTarget).filter(
([_, text]) => Object.values<string>(values).includes(text)
)
)
Object.values
が実はジェネリクスを受け取れるのでこれに string
を渡してやる。
すると Object.values
の返却型が string[]
となるので includes()
を使用しても問題なくなる。
playground
Playground のリンクを載せておくので興味がある人は触ってみると良いかも。
www.typescriptlang.org