23
26

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

【TypeScript】型ガードと型アサーションでunknown型を使い勝手良くする

Last updated at Posted at 2020-11-11

こんにちは、フロントエンドエンジニアのてりーです。
僕の詳しいプロフィールはこちら

TypwScriptを仕事で使いこなしたい人、TypeScriptの知識に不安がある人に向けて、具体的な勉強方法のロードマップをまとめました。

はじめに

TypeScript3.0から登場のunknown型。
any型から進化し、型安全は保証されていますが、
型を特定する処理を加えないと、コンパイルを通してくれません。

そこで今回はunknown型と併用して型を特定してあげる役割を持っている「型アサーション」と「型ガード」についてみていきます。

ちなみにunknownとの抱き合わせの本命は「型ガード」で、「型アサーション」はオマケ程度!って認識でOKです。

型アサーション(as)について

型アサーションとは、型定義の上書き機能です。
「アサーション=断定」の意味通り、型推論を押しのけて、型定義を上書きできるので、unknown型を上書きしてコンパイルを通すのですね。

書き方はasの後に上書きしたい型を書きます。

type Foo {
    bar: number;
    bas: string;
}

const foo = {} as Foo;
foo.bar = 123;
foo.bas = 'hello';

普通ならfooは空のオブジェクトとして生成されているので、foo.bar、foo.basは存在せずコンパイルエラーになります。

しかし、型アサーションでFoo型を上書きしているので、エラーにならない訳です。

型アサーションの危険性

大前提として、型アサーションはあまり使わない方が良いです!!!

型アサーションを使えば、任意のタイミングで型を上書きできる
→型安全性が全く保証されない

となるからです。

型アサーションの使い所

unknown型との抱き合わせは、基本的に型ガードを使う事が推奨されています。

型アサーションの使い道として、多くのコンパイルエラーをとりあえず消したい時などが有効です。
例えばJsなど型定義がないコードから、Tsへの移行時などで、型がまだちゃんと敷かれていない時などの応急処置に使うイメージですね。

型ガードについて

型ガードを使う事で、ブロック内のオブジェクトの型を制限出来ます。
そうすることで、unknown型のままではコンパイルエラーになっていた処理を安全に通す事ができます。

typeofでプリミティブ型を扱う

まず、プリミティブ型の型ガードにはtypeofを用います。


function doSomething(x: unknown) {
    if (typeof x === 'string') {

         //型ガードにより、xがstring型と判断されている為、substr()が使える
        console.log(x.substr(1)); 
    }
    //unknownのままだと、string型とは特定できないのでエラーになる
    x.substr(1);
}

instanceofでクラスインスタンスを扱う

クラスの場合はinstanceofを使います。
使い方はtypeofの時と、ほとんど一緒です。


class Base { common = 'common'; }
class Foo extends Base { foo = () => { console.log('foo'); } }
class Bar extends Base { bar = () => { console.log('bar'); } }

const doDivide = (arg: Foo | Bar) => {

  if (arg instanceof Foo) {
    arg.foo();  
    arg.bar(); //Fooの場合は、barはないのでエラー

   //instanceofはeif文の様にlseを使うことも可能
  } else {
    arg.bar();  
    arg.foo(); //Barの場合は、fooはないのでエラー
  }
  console.log(arg.common);
};
doDivide(new Foo());
doDivide(new Bar());

ユーザー定義の型ガード(is)

プリミティブ型やクラスインスタンス型と違い、オブジェクト型などに対応する型ガードはTypeScriptには用意がありません。そこで自分たちで型ガードを作る必要が出てきます。

「is」は型ガードの条件式を切り出す事ができ、ユーザー定義の型ガードと呼ばれます。

関数の返り値を引数 is Tと定義すると、
「その関数がtrueを返す場合は引数はTであり、falseを返す場合はTではない」という型ガードの条件式になります。


const bar = (arg: number | string) => {
  const isNumber = (arg: number | string): arg is number =>

    //戻り値でtrueを返しているので、argはnumber型になる
    typeof arg === "number";
};

ユーザー定義の型ガード(is)も、コンパイラに型を開発者が押し付ける事ができるという点では、
型アサーション(as)と危険度があまり変わらない為、実行時のエラーが出ない様に漏れを無くしましょう。

まとめ

any型からの反動で、とりあえず全てをコンパイルエラーしているレベルのunknown型ですが、
型アサーションと型ガードを使いこなす事で、実際に使い勝手よく書く事ができます。

独学でフロントエンドエンジニアを目指している人へ

フロントエンドの仕事を得るまでにどんな勉強をしたら良いのかをまとめました!!

興味ある方は是非ご覧ください。

23
26
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
23
26

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?