🧩
TypeScriptのArray.includesは使うな
なぜ使ってはいけないのか
早速ですがこのコードを見てください。
const arr = ['Hello'] as const
const str = 'Includes'
if (arr.includes(str)) {
console.log(`Hello ${str}`)
} else {
console.log(str)
}
実行結果は以下です。
Includes
Includesですね。
きちんと判定できています。
...そう、esbuild(型チェックなし)ならね。
やっぱり型使いたい
では型情報を見てみましょう。
エラー出ていますね。これではコンパイルできません。
コンパイルできるようにするには
ではどうするかというと...
const arr = ['Hello'] as const
const str = 'Includes'
-if (arr.includes(str)) {
+if ((arr as ReadonlyArray<string>).includes(str)) {
console.log(str) // str: Includes
} else {
console.log(str) // str: Includes
}
この部分を追加しました。
(arr as ReadonlyArray<string>)
...せっかく厳密な型にしているのに無駄になっちゃいましたね。
そしてif文内のstr
がIncludes
になっています。到達しないのに。
ちなみに
const str = 'Includes' as string
とかするとincludesで振り分けられたあともstring
になってしまいます。
これでは開発速度に影響出そうです。
Array.includesを使うな
(やっとタイトル回収)
コメントで教えていただきました
ts-resetを使うと良さそうです
組み込みの型情報を書き換えてくれる優れものです
追記: 業務で使っていますがかなり良いです。
※ここから下はts-reset関係ないです
以下のような関数を定義すると解決します。
function includes<A extends ReadonlyArray<unknown>>(array: A, input: unknown): input is A[number] {
return array.includes(input)
}
使い方はこうです。
const arr = ['Hello'] as const
const str = 'Includes'
if (includes(arr, str)) {
console.log(`Hello ${str}`)
} else {
console.log(str)
}
型はこうなります。
const arr = ['Hello'] as const
const str = 'Includes'
if (includes(arr, str)) {
console.log(`Hello ${str}`) // str: never
} else {
console.log(str) // str: 'Includes'
}
arr = ['Includes']
にすると...
const arr = ['Includes'] as const
const str = 'Includes'
if (includes(arr, str)) {
console.log(`Hello ${str}`) // str: 'Includes'
} else {
console.log(str) // str: never
}
str = 'Includes' as string
にすると...
const arr = ['Includes'] as const
const str = 'Includes' as string
if (includes(arr, str)) {
console.log(`Hello ${str}`) // str: 'Includes'
} else {
console.log(str) // str: string
}
ちゃんと型付きましたね! Hello Includes!
おわり
キャスト警察👮♀が来るので
型が付くと開発速度向上やバグ撲滅に繋がるのでas
はやめよう!
Discussion
String.includes
を使うな、ではなくArray<string>.includes
を使うな、でしょうか?仰るとおりです(疲れてたんだと思います... 修正しました)
細かいですがArray<T>.includesみたいな感じになってたと思います
Array.includeのエラーにお悩みでしたら、ts-resetの導入も良いですよ。
ちょうど該当する、読み取り専用配列に対する
.include
の型チェック改善が含まれてます。ts-resetよさそうですね!ありがとうございます
記事にも書かせていただきました
こんなのはどうでしょうか!?
結果的にこちらと変わらないので型がゆるくなるだけですね...
すみません。趣旨を理解しないまま、盛り上がってしまいました。お恥ずかしい。
arrを厳密な型のまま、includesで判定したかったわけなんですね。お役にも立てそうにないです…
ts-resetだけありがたく試させてもらいます。