Pour commencer à s’aventurer dans l’univers du Typescript, il nous faut un plan. Commençons par rassembler quelques sources:
- Le site officiel et,
dans la documentation:
- Typescript tooling in 5 minutes, qui nous donne la marche à suivre pour un “hello world”.
- Handbook, qui nous explique les concepts importants du langage.
- W3Schools a un tutoriel complet.
- TypeScript Tutorial semble, à première vue, plutôt bien fait.
Ma stratégie pour commencer est de partir du site officiel. C’est ce qui a le plus de chances d’être à jour et complet. Puis, s’il y a des choses qui nécessitent un regard différent, j’irai picorer dans les autres tutoriels – et sur StackOverflow et autres sources d’explications plus ou moins fiables, évidemment. J’éviterai juste ChatGPT, Copilot ou autres. Je préfère que mes informations, bonnes ou mauvaises, soient d’origine humanoïde.
Hello, world?
Typescript est une surcouche de Javascript, qui nécessite un
compilateur, lequel peut être obtenu par
Node.js. On va donc commencer par se procurer Node.js. Après installation
(j’ai préféré le “prebuilt” au Docker pour l’instant, ne multiplions pas
les sources de confusion) de Node.js, je peux maintenant
installer TypeScript avec:
npm install -g typescript
Jusqu’ici, tout va bien.
Je n’aime pas juste recopier l’exemple donné. Pour apprendre, il faut
un peu sortir du sentier, ça augmente les chances de se planter, et donc
de mieux cerner le fonctionnement réel de l’engin. L’exemple part d’un
fichier greeter.ts pour définir une classe, une fonction et
une interface, et manipuler le DOM de greeter.html pour y
ajouter un “Hello, …”. Essayons quelque chose d’un peu différent:
utilisons le <canvas> HTML pour afficher un rectangle
dans la fenêtre. On va donc:
- Faire un fichier
drawing.tsavec une interfaceDrawable, contenant une méthodedraw, et une classeRectanglequi implémenteDrawablevia un “contexte”canvas. Je partirai pour ça de l’exemple W3Schools sur canvas
<script>
const canvas = document.getElementById("myCanvas");
const ctx = canvas.getContext("2d");
ctx.rect(10,10, 150,100);
ctx.stroke();
</script> - Faire un fichier
drawing.htmlavec un élément<canvas>, qui sera donc rempli par le Javascript généré à partir dedrawing.js.
Fichier Typescript
Commençons par l’interface:
interface Drawable {
draw();
}Mon IDE n’est déjà pas content: il faut que je donne un type de
retour à draw(). L’exemple de la documentation n’avait que
des attributs dans l’interface, pas des méthodes. Il semble que le type
à utiliser est void, essayons.
Je veux que la classe Rectangle ait un contexte
“canvas”, une position x, une position y, une largeur et une longueur.
Quel est le type d’un “contexte canvas”? D’après un certain Yilmaz
sur StackOverflow, c’est CanvasRenderingContext2D.
L’exemple de la documentation semble montrer qu’on peut directement définir les attributs dans le constructeur, pourquoi pas. On récupère ensuite le script pour dessiner le rectangle.
class Rectangle {
constructor(private ctx: CanvasRenderingContext2D,
private x: number,
private y: number,
private w: number,
private h: number
){}
public draw(): void {
this.ctx.rect(this.x, this.y, this.w, this.h);
this.ctx.stroke();
}
}Reste à récupérer le canvas et son contexte, puis à créer et dessiner
le rectangle. On va partir du principe que le canvas a un id connu,
drawing. Lorsque je le récupère avec
document.getElementById("drawing"), je dois donner un type
à la variable dans laquelle je le met. Ca devrait être
HTMLCanvasElement, mais mon IDE n’est de nouveau pas
content si je fais:
const canvas: HTMLCanvasElement = document.getElementById("drawing");Car getElementById ne renvoie pas nécessairement le bon
type. Il peut renvoyer null, ou n’importe quel autre
sous-classe de HTMLElement. D’après ce que je comprends ici,
je peux soit ajouter un as HTMLCanvasElement pour forcer le
getElementById a être du bon type, soit utiliser une
non-null assertion avec ! qui indique “je suis
sûr que ce n’est pas null, fait moi confiance. Dans les
deux cas, je suppose que ça amènera une erreur au runtime si l’élément
n’existe pas (ou n’est pas un <canvas>), mais on se
préoccupera de ça plus tard.
Le ! ne suffit pas: il enlève le problème du
null, mais pas des autres sous-classes. Appliquons donc le
“casting”.
const canvas: HTMLCanvasElement = document.getElementById("drawing") as HTMLCanvasElement;
let rect = new Rectangle(canvas.getContext("2d")!, 100, 150, 200, 50);On utilise cette fois-ci le ! pour
getContext, cette fois il n’y a pas d’autre classe
possible. Il faudra (plus tard) regarder comment on gère proprement les
exceptions, parce que c’est tout de même un peu foireux comme manière de
faire…
Bon. Compilons !
tsc drawing.ts
J’ai maintenant un drawing.js qui a été généré.
Fichier HTML
Le fichier HTML est globalement celui de la documentation, mais avec
un <canvas> en plus:
<!DOCTYPE html>
<html>
<head>
<title>Un dessin</title>
</head>
<body>
<canvas id="drawing" width="500px" height="500px"></canvas>
<script src="drawing.js"></script>
</body>
</html>Est-ce que ça fonctionne ? Non, parce que j’ai oublié de rajouter le
rect.draw() à la fin de mon fichier .ts.
Corrigeons-le:
interface Drawable {
draw(): void;
}
class Rectangle {
constructor(private ctx: CanvasRenderingContext2D,
private x: number,
private y: number,
private w: number,
private h: number
){}
public draw(): void {
this.ctx.rect(this.x, this.y, this.w, this.h);
this.ctx.stroke();
}
}
const canvas: HTMLCanvasElement = document.getElementById("drawing") as HTMLCanvasElement;
const rect = new Rectangle(canvas.getContext("2d")!, 100, 150, 200, 50);
rect.draw();On recompile, on re-teste, et…

Ca marche !
Code:
À suivre…
Les questions en suspend pour l’instant:
- Avec la modification de l’exemple que j’ai faite, je n’utilise en
réalité pas du tout l’interface. C’est aussi bizarre, conceptuellement,
de mettre le contexte comme un attribut du rectangle. À modifier:
rajouter une classe
DrawingBoardqui sera responsable de maintenir une liste des objets à dessiner (qui utilisera donc l’interfaceDrawable) et une référence au contexte du<canvas>, et qui pourra dessiner d’un coup tous les objets. - À comprendre: comment fonctionne exactement le
!, leas, et comment faire une gestion propre des exceptions pour ne pas juste reporter le problème au runtime. - Comment introduire correctement des tests dans tout ça.