L08084のブログ

技術記事の執筆は、祈りに近い

TypeScriptでcanvas要素を扱っていたら発生したエラー: 型に呼び出しシグネチャがない式を呼び出すことはできません

f:id:l08084:20180211170429p:plain

はじめに

Angular + TypeScriptでcanvasの処理を書いていたら、下記のエラーが発生しました(3つとも同様のエラー)。

ERROR in src/app/app.component.ts(159,7): error TS2349: Cannot invoke an expression whose type lacks a call signature. Type 'string | boolean' has no compatible call signatures.
src/app/app.component.ts(178,5): error TS2349: Cannot invoke an expression whose type lacks a call signature. Type 'string | boolean' has no compatible call signatures.
src/app/app.component.ts(183,5): error TS2349: Cannot invoke an expression whose type lacks a call signature. Type 'string | boolean' has no compatible call signatures.

開発環境

  • Angular@5.2.0

  • TypeScript@2.5.3

  • VisualStudioCode@1.20.0

発生したエラーについて

上記エラーは日本語だと下記の通り表示されます。

[ts] 型に呼び出しシグネチャがない式を呼び出すことはできません。型 'string | boolean' には互換性のある呼び出しシグネチャがありません。

エラーが発生した箇所はいずれもHTML5canvasから取得したcontextからメソッドを呼び出す箇所で発生しています。

  • エラー発生箇所-1
render() {
    const ctx = this.context;
    if (ctx) {
      ctx.clearRect(0, 0, this.canpasWidth, this.canpasHeight); // <- エラー発生
      ctx.strokeStyle = 'black';
  • エラー発生箇所-2, 3
  drawBlock(x: number, y: number) {
    this.context.fillRect(this.blockWidth * x,
                          this.blockHeight * y,
                          this.blockWidth - 1,
                          this.blockHeight - 1); // <- エラー発生

    this.context.strokeRect(this.blockWidth * x,
                            this.blockHeight * y,
                            this.blockWidth - 1,
                            this.blockHeight - 1); // <- エラー発生
  }

エラー原因

canvasから取得したcontextの型を誤まってCanvas2DContextAttributesにしたのが原因でした。

  • 修正前のコード
export class AppComponent implements AfterViewInit {
context: Canvas2DContextAttributes; // <- エラー原因

  ngAfterViewInit() {
    const canvas = this.block.nativeElement;
    this.context = canvas.getContext('2d');
    setInterval(() => this.render(), 30);
  }
}

contextの型をCanvasRenderingContext2Dに修正したところエラーが全部消えて正しく稼働しました。

  • 修正後のコード
export class AppComponent implements AfterViewInit {
context: CanvasRenderingContext2D; // <- CanvasRenderingContext2Dに修正するとエラーが消える

  ngAfterViewInit() {
    const canvas = this.block.nativeElement;
    this.context = canvas.getContext('2d');
    setInterval(() => this.render(), 30);
  }
}

参考にしたサイト

qiita.com