🔧

TypeScriptのconstructorで非同期処理をしたくなったら

2021/09/27に公開

はじめに

TSのconstructorを書いていて、一部awaitで値をセットしようとしたらできませんでした。
ということで、初期化用の非同期メソッドを用意して、その中でawaitを使う処理を行うように変更して返すことにしました。

これ、よくやるのですが、たまに忘れるので備忘録として記事にしておこうと思います。

結論

  • constructorにはasyncに利用できない
    • 'async' modifier cannot appear on a constructor declaration.(1089) が発生する
  • 初期化時に非同期処理(外部APIをコールした結果を取得するなど)を行う際には、初期化用のメソッドを定義する

やってみたこと

constructorでawaitできない、という状況の再現

class Fruits {
    name: string;
    price: number;

    constructor( name:string ){
        this.name = name;
        this.price = await this.setPrice();
    }

    private async setPrice(){
        return setTimeout( () => { Math.floor(Math.random() * 100 ) }, 3000); // 時間がかかる処理;
    }
}

const main = async() => {
    const apple = new Fruits('apple');
    console.log( apple.price );
}

main();

Playground Link
constructorにasyncがないので、当然awaitは使えません。 'await' expressions are only allowed within async functions and at the top levels of modules.(1308) が出ます。

では、constructorにasyncをつければいいのでは?と思ったのでやってみます。

class Fruits {
    name: string;
    price: number;

    async constructor( name:string ){
        this.name = name;
        this.price = await this.setPrice();
    }

    private async setPrice(){
        return setTimeout( () => { Math.floor(Math.random() * 100 ) }, 3000); // 時間がかかる処理;
    }
}

const main = async() => {
    const apple = new Fruits('apple');
    console.log( apple.price );
}

main();

Playground Link
constructorにはasyncを使えません。コレだと 'async' modifier cannot appear on a constructor declaration.(1089) が出ます。

初期化用のメソッドを用意する場合

class Fruits {
    name: string;
    price: number;

    constructor(){
        this.name = "";
        this.price = 0;
    }

    public static async build( name:string ): Promise<Fruits>{
        const fruit = new Fruits();
        fruit.name = name;
        fruit.price = await this.setPrice();
        return fruit;
    }

    private static async setPrice(){
        return setTimeout( () => { Math.floor(Math.random() * 100 ) }, 3000); // 時間がかかる処理;
    }
}

const main = async() => {
    const apple:Fruits = await Fruits.build( 'apple');
    console.log( apple.price );
}

main(); // e.g. 17879

Playground Link

参考

必要な1次ソースがすぐ見つけられなかったので、勝手ながら下記ブログを参考にさせていただきました。分かりやすかったです。

Discussion