🐥

【TS】呪文:undefined as unknown as numberとは?

2023/05/31に公開

【TS】呪文:undefined as unknown as numberとは?

先日、業務中にいつも親切に教えてくださる上司から、上記のundefined as unknown as numberという呪文を教わりました。まるで呪文のように、もしくは英会話の文法のように聞こえます。また、上司曰く、悪用は厳禁な呪文でもあるようです。それでは、この呪文の意味は一体なんなのか、またなぜ悪用厳禁な呪文であるのか、を理解していきましょう。

1. そもそも "as"とは?

asは、型アサーションと言って、TypeScriptの型推論を上書きする機能になります。
タイトルの例だと、undefined as unknownとすることで、undefinedという値をunknown型とすることで、tscに型を直接、伝えることができます。

以下、サバイバルTypeScriptからの引用です。

型アサーション「as」(type assertion)
TypeScriptには、型推論を上書きする機能があります。その機能を型アサーション(type assertion)と言います。
TypeScriptコンパイラーはコードをヒントに型を推論してくれます。その型推論は非常に知的ですが、場合によってはコンパイラーよりもプログラマーがより正確な型を知っている場合があります。そのような場合は、型アサーションを用いるとコンパイラーに型を伝えることができます。型アサーションはコンパイラに「私を信じて!私のほうが型に詳しいから」と伝えるようなものです。

2. unknown型の持つ型アサーションの回避テクニックについて

前提知識: unknownに関して

TypeScriptのunknown型は、型が何かわからないときに使う型です。
unknown型はまだ何の型なのか不明で、必ず何かの型に変換してから使わなければならないことを表す型になります。
その性質上、unknown型のデータをキャストする際には全く互換性のチェックが行われないため、unknown型からのキャスト先の型の正しさはプログラマーが担保する必要があります。
また、unknown型へのキャストも制限なくできるので、意図的に(大抵の場合正しいはずの)型を剥がして任意の型を付け直す、という危険なことができてしまいます。
ですので、極力使わない方がよく、使う場合は、注意して扱う必要がある型になります。

any型とunknown型の違い

any型とunknown型の違いはこちらにて確認いただけます。

型アサーション回避テクニックについて

タイトルにある呪文を読み解いていきます。
今回は、string型の数値が入った文字列("12345")をnumber型として扱いたい時に、型アサーションを使ってnumber型に変換していければと思います。

通常の型アサーションの場合

まずは、通常の型アサーションのように、以下のコードをVSCodeに書いてみます。
実行コード

const str = "12345";
const num = str as number;

VSCodeの画面

すると、VSCodeの画面では、こちらのエラーが出てきました。

Conversion of type 'string' to type 'number' may be a mistake because neither
type sufficiently overlaps with the other. If this was intentional, convert 
the expression to 'unknown' first.ts(2352)

エラーの理由としては、定数strが明らかにstring型であるのにも関わらず、その値をnumber型として型アサーションしようとしているためです。

呪文を使ってみた場合

上述の通常の型アサーションの場合、string型の定数をnumber型としてアサーションできず、エラーになってしまいました。そのエラーを回避する方法が今回の呪文になります。
unknown型は型が何か分からないときに使う型であることから、「どんな型にも型アサーションできる」 といった特徴があります。ですので、string型の定数strを一度、unknown型にアサーションしてから、number型に再度、アサーションすればエラーを無くすことができます。ちなみにですが、この2回アサーションすることをダブルアサーションと呼びます。

ダブルアサーションでの実行コード

const str = "12345";
const num = str as unknown as number;

呪文(unknownを用いたダブルアサーション)が悪用厳禁な理由

str as unknown as numberで行っていることはキャスト(あるデータ型の変数を別のデータ型に変換する型変換のこと)ではなく、あくまでTypeScriptにas以降の型であることを伝えているだけなので、型安全性の面では不安要素が残ってしまいます。ですので、型チェック時にエラーを起こしてしまうバグのきっかけになってしまう可能性すらあります。
↓これから、ダブルアサーションが悪用厳禁な理由をより深く解説していきます。

ダブルアサーションの動作について

文字だけでは分かりにくいと思うので、実際にTS Playgroundにてダブルアサーションを動かしてみます。
今回は、上記のダブルアサーションの実行コードのnumの値と型を確認してみようと思います。
実行コード

const str = "12345";
const num = str as unknown as number;
console.log(num)
console.log(typeof num)

TS Playground 実行結果

注意ポイント1

実行結果にあるように、numの型はstring型のままになっているのです!
もしこれをnumber型として扱ってコードを書いていってしまったら、バグを引き起こしてしまうかもしれません。

注意ポイント2

定数numの上にカーソルを当てると、number型になっています!

実際はstring型ですが、それを開発時に別のチームメンバーが気づかずにコードを書いてしまい、バグを引き起こしてしまうかもしれません。

Tips

通常の型アサーション時のVSCodeの画面にて、エラーにカーソルを当ててquick fixを実行すると、今回のタイトルの呪文に置き換わります。

参考記事

↓こちらの記事の説明が分かりやすいので、併せて確認いただくと理解が深まると思います!
サバイバルTypeScript 型アサーションの制約を回避する

最後に

呪文の解読や、悪用厳禁な理由を理解することができましたでしょうか?
また、こちらの記事が初めてのzennへの投稿になります。
少しでも面白いな〜、タメになった〜と思っていただけたら幸いです!

株式会社モニクル

Discussion