はじめに
typescriptのasについて、その意味はわかっていたが、使用する場面について理解していなかったので調べた際の記録。
結論
as
は基本使わない。
as
を使っていいのは書いたコードが正しいのにも関わらず、TypeScriptがそれを推論できていない場合のみ。
as
をもし使うとしても、その影響範囲を小さい関数に閉じ込める。
詳細
まず、as
は型情報を強制的に修正するものである。(型アサーション(Type Assertion))
例えば、以下のような引数に渡したオブジェクトをコピーして新しいオブジェクトをつくる関数があるとする。
function shallowCopy<T extends object>(obj: T): T {
const result = {};
for (const key in obj) {
result[key] = obj[key];
}
return result;
}
パッと見は問題なさそうだが、TypeScriptでエラーがでる。
Type 'Extract<keyof T, string>' cannot be used to index type '{}'.
↓
const result = {};
の時点でresult
は{}
だと推論しているので、そのindex
に'Extract<keyof T, string>'
は使用できない
この部分については別の記事に詳細を書きました。
Type '{}' is not assignable to type 'T'. '{}' is assignable to the constraint of type 'T', but 'T' could be instantiated with a different subtype of constraint 'object'.
↓
型'{}'は型'T'に割り当て可能ではありません。'{}'は型'T'の制約に割り当て可能ですが、'T'は制約'object'の異なるサブタイプでインスタンス化される可能性があります。
のエラーがでます。
要は、return result;
しているresult
がfunction shallowCopy<T extends object>(obj: T): T
の型定義ではTとなっているが、関数内では{}
に推論されている為に出ているエラーです。
解決
これは、「書いたコードが正しいのにも関わらず、TypeScriptがそれを推論できていない場合」の場合に該当するため、as
を使って解決しても良さそう。
const result = {} as T;
と型アサーション(Type Assertion)を使ってresult
の型をTに上書きすることで上記のエラーが解決する。
おわりに
なんとなく「あまり使ってはいけないもの」という印象があったが、その通りであり、その理由もよくわかった。
同時にExtract
などの理解も得られて為になった。