web-dev-qa-db-fra.com

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

Je teste simplement TypeScript dans VisualStudio 2012 et j'ai un problème avec son système de types. Mon site html a une balise canvas avec l’id "mycanvas". J'essaie de dessiner un rectangle sur cette toile. 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 la valeur de type 'HTMLElement'

Cela marque la deuxième ligne comme une erreur. Je pensais que ce serait simplement un avertissement mais le code ne compile pas. VisualStudio dit que 

il y avait des erreurs de construction. Voulez-vous continuer et lancer le dernier construction réussie?

Je n'ai pas aimé cette erreur du tout. Pourquoi n'y a-t-il pas d'invocation de méthode dynamique? 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. Je viens d'ajouter 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 types n'était toujours pas satisfait. Voici le nouveau message d'erreur, cette fois dans la première ligne:

Impossible de convertir 'HTMLElement' en 'HTMLCanvasElement': Tapez 'HTMLElement' manque la propriété 'toDataURL' dans le type 'HTMLCanvasElement'

Eh bien, je suis partant pour le typage statique, mais cela rend le langage inutilisable. Qu'est-ce que le système de types veut que je fasse?

METTRE À JOUR:

TypeScript n’a en effet aucun support pour l’appel dynamique et mon problème peut être résolu avec des diffusions de type. Ma question est fondamentalement une copie de celle-ci TypeScript: casting HTMLElement

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

ou en utilisant la recherche dynamique avec le type any (sans vérification typographique):

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

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

173
Markus Jarderot

Il semble que cela soit 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-constantes-and-compiler-performance.aspx Voir la section "Surcharge en Constantes" où la balise canvas est explicitement affichée.

2
Chris
const canvas =  document.getElementById('stage') as HTMLCanvasElement;
1
Halil Kocaerkek

J'ai le même problème, mais avec SVGSVGElement au lieu de HTMLCanvasElement. La conversion en SVGSVGElement a généré une erreur de compilation:

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

Impossible de convertir 'HTMLElement' en 'SVGSVGElement':
Le type 'HTMLElement' manque dans la propriété 'width' du type 'SVGSVGElement'.
Le type 'SVGSVGElement' est manquant dans la propriété 'onmouseleave' du type 'HTMLElement'.

Si le fixe par le premier casting en 'any':

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

ou de cette façon (il a le même effet)

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

Maintenant, mySvg est fortement typé SVGSVGElement.

1
Edward

Tandis que d’autres réponses promeuvent des assertions de type (c’est ce qu’elles sont - TypeScript n’a pas type de fontes qui modifient réellement le type; elles ne sont qu’un moyen de supprimer les erreurs de vérification de type), la manière honnête Le problème est d'écouter les messages d'erreur.

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

  • document.getElementById("mycanvas") peut renvoyer null, car aucun noeud de cet identifiant n'a été trouvé (il peut avoir été renommé, mais pas encore injecté dans le document, quelqu'un aurait peut-être essayé d'exécuter votre fonction dans un environnement sans accès à DOM)
  • document.getElementById("mycanvas") peut renvoyer une référence à un élément DOM, mais cet élément DOM n'est pas une HTMLCanvasElement
  • document.getElementById("mycanvas") a retourné une HTMLElement valide, il s'agit bien d'une HTMLCanvasElement, mais le CanvasRenderingContext2D n'est pas pris en charge par le navigateur.

Au lieu de demander au compilateur de se taire (et éventuellement de vous retrouver dans une situation où un message d'erreur inutile comme Cannot read property 'getContext' of null est émis), je vous 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;
}

Usage:

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

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

Voir TypeScript Playground .

0
Karol Majewski