Async Await in Typescript

# はじめに

最近、Typescirptを使い始めた若輩者ですが、もう型がないと息ができないくらいTypescriptに嵌まってしまいました。
今回はTypescriptの機能の一つであるAsync/Awaitを紹介します。

ES6にはPromiseがあり、非同期処理が非常に簡単に書けるようになりました。
しかし、ECMAScriptはさらなる高みを目指しているみたいです。
より発展的に非同期処理を記述できるようにするために、Async/Awaitを提案し、すでにstage3に入ってきています。

Babelでは、`babel-preset-es2017` もしくは `babel-plugin-transform-async-to-generator`を利用することで使用することができるみたいです。

ECMAScriptのSupersetであるTypescriptも、Async/Awaitをサポートしています。(v1.6~)

Promiseによって、充分、非同期処理が簡単に書けるのですが、
Async/Awaitはさらに簡略で、より慣れた手続き的な書き方で書けるようになります。



### 動作環境
Typescript v2.1.4

### Async/Awaitのサポート

今までは compilerOptionsの target を es6 に指定しないと、typescriptでAsync/Awaitをコンパイルできませんでした。
そのため、ブラウザ環境向けに利用するには、TypescirptからES6にコンパイルして、さらにBabelでトランスパイルするような過程が必要だったりしたですが、v2.1より es5/es3に指定してもコンパイルできるようになりました。
これにより、より気軽にAsync/Awaitが使えるようになりましたね。

[What's New TypeScript 2.1 
](https://www.typescriptlang.org/docs/handbook/release-notes/typescript-2-1.html)


v1.6から `--experimentalAsyncFunctions`オプション付きでサポートを開始
v1.7からオプションなし、"target": "es6" 限定でサポート
v2.1から "target": "es5/es3"でサポート





## 使ってみる

2秒間待ってから "wait" と出力するwait関数を3回直列で実行するサンプルを書いてみます。

まず、Promiseで書いてみます。

```ts:promise.ts
// Promiseを返す非同期関数
function wait(): Promise<any> {
  return new Promise(resolve => {
    setTimeout(() => {
      console.log('wait');
    }, 2000);
  })
}

function main() {
  return wait()
    .then(() => {
      return wait();
    })
    .then(() => {
      return wait();
    });
}

main();

```

コールバックを用いた書き方よりはだいぶいいのですが、returnが多かったり、何度もthenをして、少し冗長な気がします。
上記のmain関数をAsync/Awaitを用いた書き方で書き直してみます。

```ts:async.ts

// functionの前にasyncを書くとasync関数になります。
async function main() {
  await wait();
  await wait();
  await wait();
}

main();


```


.then()もなく、かなりスッキリした書き方になりました。

このように、Async関数の中でPromiseを返す関数の前に`await`をつけるとその関数の処理が終わるまで待ってくれます。



Async/Awaitはこのようなシンプルな記述をだけでなく、Promiseでは難しいより慣れた手続き的な表現ができます。

Promiseでは処理の結果をresolve()でPromiseに包んで.then()のコールバック関数の引数として次の処理につなげることができますが、Async/Awaitを使えば、あたかも同期関数のように = で代入するような記述ができます。

```ts
//42がラップされたPromiseを返す関数
function foo() {
  return Promise.resolve(42);
}


function main() {
  foo().then(num => {
    console.log(num); //=> 42
  });
}
main();

async function main2() {
  // あたかも普通の同期関数のように = で代入できる
  const num = await foo();
  console.log(num); //=> 42

  // ちなみに型推論もちゃんとやってくれる
  typeof(num) === 'number' //=> true
}

main2();

```


また、Promiseでのチェーンでは途中で処理を終了したい時などには.reject()して.catch()するなど工夫が必要です。

しかし、Async/Awaitならば、通常の手続き処理のようにif文やswitch文、変数代入に利用できるので、自在に処理を切り分けたり、中断させることができます。

```ts

async function foo() {
  // if文で使ったり
  if (await model.exists()) {
  
  }
  // そのまま関数に渡したり
  bar(await foo());

  // 返り値の配列をそのまま参照
  let result = (await bar())[0]
}

```


async関数はそれ自体が何もしなくても自動的にPromiseを返すので、async関数の実行に続けて、.then()かawaitを書くことができます。

```ts

// Promiseを返すasync関数
async foo() {
  return wait();
}

// .then()で続ける
foo().then(() => {
   foo();
});

// awaitで待つ
async main() {
  await foo();
}


```

いかがでしょうか。
その他、Async/Awaitは様々なパターンの関数やメソッドに利用できます。

```ts

// アロー関数をAsync関数化
async () => {
  await this.foo();
}


// クラスのメソッドにもasyncが書ける
class Foo {

  async bar() {
    await this.wait();
  }

  static async bar() {
    await wait();
  }
}



```



とてつもなく簡単に非同期処理が書けるので、気持ちよくコードを書くことができます。

ぜひ使ってみてください。



参考
[公式ドキュメント](https://www.typescriptlang.org/docs/handbook/release-notes/typescript-1-7.html)
[JavaScriptは如何にしてAsync/Awaitを獲得したのか Qiita版](http://qiita.com/gaogao_9/items/5417d01b4641357900c7)