web-dev-qa-db-ja.com

TypeScript:型システムの問題

VisualStudio 2012でTypeScriptをテストしているだけで、そのタイプシステムに問題があります。私のhtmlサイトには、「mycanvas」というIDのcanvasタグがあります。このキャンバスに長方形を描画しようとしています。ここにコードがあります

var canvas = document.getElementById("mycanvas");
var ctx: CanvasRenderingContext2D = canvas.getContext("2d");
ctx.fillStyle = "#00FF00";
ctx.fillRect(0, 0, 100, 100);

残念ながらVisualStudioは

プロパティ「getContext」は、タイプ「HTMLElement」の値には存在しません

2行目をエラーとしてマークします。これは単なる警告だと思ったが、コードはコンパイルされない。 VisualStudioによると

ビルドエラーがありました。最後に成功したビルドを継続して実行しますか?

このエラーはまったく気に入らなかった。動的なメソッド呼び出しがないのはなぜですか?すべてのメソッドgetContextは、キャンバス要素に間違いなく存在します。しかし、この問題は簡単に解決できると思いました。 canvasに型注釈を追加しました:

var canvas : HTMLCanvasElement = document.getElementById("mycanvas");
var ctx: CanvasRenderingContext2D = canvas.getContext("2d");
ctx.fillStyle = "#00FF00";
ctx.fillRect(0, 0, 100, 100);

しかし、型システムはまだ満足していませんでした。これが新しいエラーメッセージです。今回は1行目です。

「HTMLElement」を「HTMLCanvasElement」に変換できません。タイプ「HTMLElement」には、タイプ「HTMLCanvasElement」のプロパティ「toDataURL」がありません

まあ、私は静的型付けに全力を尽くしていますが、これにより言語が使用できなくなります。型システムは私に何をして欲しいのですか?

更新:

TypeScriptは実際に動的呼び出しをサポートしておらず、タイプキャストで私の問題を解決できます。私の質問は基本的にこれの複製です TypeScript:cast HTMLElement

82
lhk
var canvas = <HTMLCanvasElement> document.getElementById("mycanvas");
var ctx = canvas.getContext("2d");

またはanyタイプで動的ルックアップを使用する(タイプチェックなし):

var canvas : any = document.getElementById("mycanvas");
var ctx = canvas.getContext("2d");

lib.d.ts でさまざまなタイプを見ることができます。

189
Markus Jarderot
const canvas =  document.getElementById('stage') as HTMLCanvasElement;
3
Halil Kocaerkek

これはTypeScriptの.9バージョンで修正されているようです: http://blogs.msdn.com/b/TypeScript/archive/2013/03/25/working-on-TypeScript-0-9- generics-overload-on-constants-and-compiler-performance.aspx canvasタグが明示的に示されている「定数のオーバーロード」のセクションを参照してください。

2
Chris

他の答えは型アサーションを促進します(それが、TypeScriptには実際に型を変更する型キャストがありません;それらは単に型チェックエラーを抑制する方法です)あなたの問題にアプローチする知的に正直な方法は、エラーメッセージを聞くことです。

あなたの場合、うまくいかない可能性がある3つのことがあります:

  • document.getElementById("mycanvas")nullを返す場合があります。これは、そのIDのノードが見つからないためです(名前が変更され、まだドキュメントに挿入されていない、誰かがアクセスなしの環境で関数を実行しようとした可能性があります) DOMへ)
  • document.getElementById("mycanvas")はDOM要素への参照を返す場合がありますが、このDOM要素はHTMLCanvasElementではありません
  • document.getElementById("mycanvas")は有効なHTMLElementを返しましたが、実際にはHTMLCanvasElementですが、CanvasRenderingContext2Dはブラウザでサポートされていません。

コンパイラーにシャットダウンするように指示する代わりに(そしておそらく、Cannot read property 'getContext' of nullがスローされます)、アプリケーションの境界を制御することをお勧めします。

要素にHTMLCanvasElementが含まれていることを確認してください

const getCanvasElementById = (id: string): HTMLCanvasElement => {
    const canvas = document.getElementById(id);

    if (!(canvas instanceof HTMLCanvasElement)) {
        throw new Error(`The element of id "${id}" is not a HTMLCanvasElement. Make sure a <canvas id="${id}""> element is present in the document.`);
    }

    return canvas;
}

ブラウザでレンダリングコンテキストがサポートされていることを確認してください

const getCanvasRenderingContext2D = (canvas: HTMLCanvasElement): CanvasRenderingContext2D => {
    const context = canvas.getContext('2d');

    if (context === null) {
        throw new Error('This browser does not support 2-dimensional canvas rendering contexts.');
    }

    return context;
}

使用法:

const ctx: CanvasRenderingContext2D = getCanvasRenderingContext2D(getCanvasElementById('mycanvas'))

ctx.fillStyle = "#00FF00";
ctx.fillRect(0, 0, 100, 100);

TypeScript Playground を参照してください。

1
Karol Majewski

同じ問題がありましたが、HTMLCanvasElementの代わりにSVGSVGElementを使用しました。 SVGSVGElementにキャストすると、コンパイル時エラーが発生しました。

var mySvg = <SVGSVGElement>document.getElementById('mySvg');

「HTMLElement」を「SVGSVGElement」に変換できません:
タイプ「HTMLElement」には、タイプ「SVGSVGElement」のプロパティ「width」がありません。
タイプ「SVGSVGElement」には、タイプ「HTMLElement」のプロパティ「onmouseleave」がありません。

最初に「any」にキャストして修正した場合:

var mySvg = <SVGSVGElement><any>document.getElementById('mySvg');

またはこの方法(同じ効果があります)

var mySvg: SVGSVGElement = <any>document.getElementById('mySvg');

現在、mySvgはSVGSVGElementとして強く型付けされています。

1
Edward