114 votes

TypeScript : problèmes avec le système de types

Je suis en train de tester Typescript dans VisualStudio 2012 et j'ai un problème avec son système de types. Mon site html possède une balise canvas avec l'id "mycanvas". J'essaie de dessiner un rectangle sur ce canevas. Voici le code

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

Malheureusement, VisualStudio se plaint que

la propriété 'getContext' n'existe pas sur une valeur de type HTMLElement

Il marque la deuxième ligne comme une erreur. Je pensais qu'il s'agirait simplement d'un avertissement, mais le code ne compile pas. VisualStudio dit que

il y avait des erreurs de construction. Voulez-vous continuer et exécuter la dernière construction réussie ?

Je n'ai pas du tout aimé cette erreur. Pourquoi n'y a-t-il pas d'invocation dynamique de méthodes ? Après tout, la méthode getContext existe bel et bien sur mon élément canvas. Cependant, je pensais que ce problème serait facile à résoudre. J'ai simplement ajouté une annotation de type pour canvas :

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

Mais le système de type n'était toujours pas satisfait. Voici le nouveau message d'erreur, cette fois à la première ligne :

Impossible de convertir 'HTMLElement' en 'HTMLCanvasElement' : Type La propriété 'toDataURL' de 'HTMLElement' est manquante dans le type HTMLCanvasElement

Je suis tout à fait favorable au typage statique, mais cela rend le langage inutilisable. Qu'est-ce que le système de types veut que je fasse ?

UPDATE :

Typescript n'a en effet aucun support pour l'invocation dynamique et mon problème peut être résolu avec des typcasts. Ma question est essentiellement une duplication de celle-ci TypeScript : casting HTMLElement

248voto

Markus Jarderot Points 33893
var canvas = <HTMLCanvasElement> document.getElementById("mycanvas");
var ctx = canvas.getContext("2d");

ou en utilisant la recherche dynamique avec l'option any type (pas de vérification du type) :

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

Vous pouvez consulter les différents types dans lib.d.ts .

17voto

Halil Kocaerkek Points 171
const canvas =  document.getElementById('stage') as HTMLCanvasElement;

13voto

Karol Majewski Points 4839

Alors que d'autres réponses font la promotion des assertions de type (c'est ce qu'elles sont - TypeScript n'a pas d'assertions de type). transferts de type qui changent réellement le type ; ils sont simplement un moyen de supprimer les erreurs de vérification de type), la façon intellectuellement honnête d'aborder votre problème est d'écouter les messages d'erreur.

Dans votre cas, il y a 3 choses qui peuvent mal tourner :

  • document.getElementById("mycanvas") pourrait revenir null parce qu'aucun nœud de cet id n'est trouvé (il a peut-être été renommé, pas encore injecté dans le document, quelqu'un a peut-être essayé d'exécuter votre fonction dans un environnement sans accès au DOM).
  • document.getElementById("mycanvas") peut renvoyer une référence à un élément DOM, mais cet élément DOM n'est pas un fichier de type HTMLCanvasElement
  • document.getElementById("mycanvas") a retourné un valide HTMLElement il s'agit en effet d'un HTMLCanvasElement mais le CanvasRenderingContext2D n'est pas pris en charge par le navigateur.

Au lieu de dire au compilateur de se taire (et de vous retrouver éventuellement dans une situation où un message d'erreur inutile tel que Cannot read property 'getContext' of null est lancée), je recommande de prendre le contrôle des limites de votre application.

Assurez-vous que l'élément contient un 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;
}

Assurez-vous que le contexte de rendu est pris en charge par le navigateur.

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;
}

Uso:

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

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

Ver Terrain de jeu TypeScript .

2voto

Chris Points 1507

Il semble que ce problème ait été corrigé dans la version .9 de TypeScript : http://blogs.msdn.com/b/typescript/archive/2013/03/25/working-on-typescript-0-9-generics-overload-on-constants-and-compiler-performance.aspx Voir la section "Surcharge des constantes" où la balise canvas est explicitement indiquée.

1voto

Edward Points 1522

J'ai eu le même problème, mais avec SVGSVGElement au lieu de HTMLCanvasElement. La transformation en SVGSVGElement donne une erreur de compilation :

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

Impossible de convertir 'HTMLElement' en 'SVGSVGElement' :
Il manque la propriété 'width' au type 'HTMLElement' du type 'SVGSVGElement'.
Il manque la propriété "onmouseleave" au type "SVGSVGElement" du type "HTMLElement".

Je l'ai corrigé en le coulant d'abord dans 'any' :

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

ou de cette façon (l'effet est identique)

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

Maintenant monSvg est fortement typé comme SVGSVGElement.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X