Premiers pas en TypeScript
TypeScript 101, Télécom Paris
| Séance | Date | Horaire | Salle |
|---|---|---|---|
| 1 : Premiers pas | mar. 09/02/2027 | 8 h 30 à 11 h 45 | à compléter |
| 2 : Fonctions, objets et tableaux | ven. 12/02/2027 | 8 h 30 à 11 h 45 | à compléter |
| 3 : Programmation orientée objet | mar. 23/02/2027 | 8 h 30 à 11 h 45 | à compléter |
| 4 : Évaluation 1 | ven. 05/03/2027 | 8 h 30 à 11 h 45 | à compléter |
| 5 : Données et erreurs | mar. 09/03/2027 | 8 h 30 à 11 h 45 | à compléter |
| 6 : Asynchrone et réseau | mar. 16/03/2027 | 8 h 30 à 11 h 45 | à compléter |
| 7 : Applications complètes | ven. 26/03/2027 | 15 h 30 à 17 h | à compléter |
| 8 : Évaluation 2 | jeu. 29/04/2027 | 8 h 30 à 11 h 30 | à compléter |
Pause de 10 h à 10 h 15 pendant les séances du matin.
Encadrants : Rémi Sharrock, second encadrant à compléter.
Pas de projet ni de rendu noté : la note finale est la moyenne des deux évaluations. Ces modalités ne changent pas en cours de période.
hello.ts
La seule nouveauté face à JavaScript : les : string, : number, : boolean.
Ce sont des annotations de type. Elles disent au compilateur ce que chaque variable a le droit de contenir.
Un .ts ne s’exécute jamais directement : il faut toujours deux temps.
hello.ts ──(tsc)──> hello.js ──(node)──> résultat
│ ^
└───────────────(tsx)───────────────────┘
| Commande | Ce qu’elle fait |
|---|---|
node |
exécute du JavaScript hors navigateur |
npm |
installe des paquets |
npx |
lance un outil installé dans le projet |
tsc |
traduit .ts → .js |
tsx |
traduit et exécute d’un coup |
npx répond à « où est l’outil ? ». tsc / tsx répondent à « qu’est-ce que j’en fais ? ».
npx, en une phrasenpm install range l’outil dans node_modules : il n’existe pas dans votre terminal pour autant.
| Installé | Vous tapez |
|---|---|
| globalement sur la machine | tsc |
| dans le projet | npx tsc |
Machines de l’école : toujours npx.
tsc ou tsx ? Une lettre, deux effets| Commande | Affiche quelque chose ? | Laisse un .js ? |
|---|---|---|
tsc hello.ts |
non | oui |
node hello.js |
oui | non |
tsx hello.ts |
oui | non |
Rien ne s’affiche après tsc ?
C’est normal : tsc produit un fichier, il n’exécute rien. Enchaînez avec node hello.js.
Gardez tsc en tête : c’est lui qui vérifie les types.
| Entrée | Sortie | |
|---|---|---|
Compilation : gcc sur du C |
code source | binaire, exécuté par le processeur |
Transpilation : tsc sur du TypeScript |
code source | code source, en JavaScript |
tsc produit du JavaScript lisible. Ouvrez hello.js : vous comprendrez tout.
Le JavaScript produit ne contient plus aucune trace du système de types. On parle d’effacement de types.
Conséquence décisive
Les types ne vous protègent pas à l’exécution. Ils vous protègent contre les incohérences de votre propre code, et cette protection s’arrête à la frontière du programme : JSON, réseau, formulaires.
| Type | Description | Exemple |
|---|---|---|
| tableau | même type, taille libre | number[] ou Array<number> |
| tuple | taille et types fixés par position | [string, number] |
| enum | constantes nommées | enum Couleur { Rouge, Vert } |
| Type | Sens | Quand |
|---|---|---|
void |
ne retourne rien | fonctions à effet |
null |
absence voulue | valeur vidée explicitement |
undefined |
jamais affectée | rarement écrit à la main |
unknown |
inconnu mais sûr | JSON, réseau, formulaire |
any |
désactive la vérification | presque jamais |
never |
ne retourne jamais | lève toujours une erreur |
any fait taire le compilateur : vous perdez tout le bénéfice de TypeScript. Face à l’inconnu, prenez unknown : il vous oblige à vérifier.
| Notation | Nom | Exemple |
|---|---|---|
| |
union | let id: string | number; |
type |
alias | type Point = { x: number; y: number }; |
“a” | “b” |
types littéraux | type Direction = “nord” | “sud”; |
Direction n’accepte que ces deux chaînes, et l’éditeur vous les propose.
Écrites avec des backticks, elles remplacent la concaténation.
Backtick : AltGr+7 sur AZERTY PC, Option+è sur Mac. C’est une touche morte : rien ne s’affiche avant la touche suivante.
Le $ seul ne suffit pas. `Bonjour $nom` affiche littéralement $nom. Les accolades sont obligatoires.
| Concept | C | TypeScript |
|---|---|---|
| Variable | int age = 25; |
const age: number = 25; |
| Chaîne | char* nom = "Alice"; |
const nom: string = "Alice"; |
| Tableau | int tab[5]; |
const tab: number[] = []; |
| Fonction | int add(int a, int b) |
function add(a: number, b: number): number |
const ou let, jamais avec le type:number : ni int, ni floatstring est un vrai type, pas un tableau de caractèresDébutant : annotez, cela force à réfléchir au type. Toujours : annotez les signatures de fonctions.
Au chapitre 1.1, node exécutait le code dans un terminal. Ici, le même code s’exécute dans un navigateur et peut modifier la page affichée.
La porte d’entrée s’appelle document.
document n’existe que dans le navigateur
Un fichier qui manipule document et lancé avec node plante : ReferenceError: document is not defined.
Ce n’est pas une erreur de type, c’est une erreur d’environnement.
Tout en bas de la page :
On lie app.js, jamais app.ts : un navigateur ne lit pas le TypeScript. Sans l’étape tsc, la page s’affiche et rien ne réagit.
Ouvrez la console avec F12 : c’est là qu’écrit console.log, et là que s’affichent les erreurs.
| Question de l’assistant | Réponse |
|---|---|
| How would you like to start? | Empty |
| Install dependencies? | Yes |
| Initialize a git repository? | au choix |
| Add AI agent files? | No |
Ouvrez l’adresse affichée, en général http://localhost:4321.
mon-site/
├── src/
│ ├── pages/ # une page = un fichier .astro
│ └── scripts/ # vos fichiers .ts : à créer vous-même
└── package.json
Dans src/pages/index.astro, on charge directement le TypeScript :
Astro transpile à la volée et recharge la page à chaque enregistrement.
| Rôle | Balises |
|---|---|
| Structure | <header> <nav> <main> <section> <footer> |
| Texte | <h1>…<h6> <p> <span> |
| Conteneurs | <div> (bloc), <span> (en ligne) |
| Listes | <ul> <ol> <li> |
| Formulaires | <form> <label> <input> <button> |
| Liens, images | <a> <img> |
<strong> et <b> donnent le même gras, mais <strong> dit pourquoi. Préférez toujours la balise sémantique.
id et class| Attribut | Rôle |
|---|---|
id |
identifiant unique : c’est par lui que TypeScript retrouve un élément |
class |
étiquette partagée, ciblée par le CSS |
href / src |
destination d’un lien, source d’une image ou d’un script |
for |
relie un <label> au champ portant cet id |
Trois sélecteurs suffisent pour commencer :
as HTMLHeadingElement est une assertion de type : vous affirmez au compilateur ce qu’il ne peut pas deviner à partir d’une chaîne.
getElementById renvoie null si l’id n’existe pas : une faute de frappe suffit. L’assertion as ne vérifie rien à l’exécution. D’où le if systématique.
innerHTML et données extérieures
Une chaîne venue d’un formulaire, d’une URL ou d’une API peut contenir du code qui s’exécutera dans la page : c’est une faille XSS.
textContent par défaut. innerHTML seulement pour du HTML que vous écrivez.
Un élément créé n’apparaît nulle part tant qu’il n’est pas inséré.
C’est l’oubli le plus fréquent : le code tourne sans erreur, et rien ne s’affiche.
let compteur: number = 0;
const affichage = document.getElementById("compteur") as HTMLParagraphElement;
const bouton = document.getElementById("btn") as HTMLButtonElement;
if (bouton && affichage) {
bouton.addEventListener("click", function () {
compteur = compteur + 1;
affichage.textContent = `Compteur : ${compteur}`;
});
}Vous n’appelez jamais cette fonction : c’est le navigateur qui l’appellera. On parle de fonction de rappel.
| Événement | Déclencheur |
|---|---|
click |
clic sur l’élément |
input |
saisie, à chaque caractère |
change |
valeur modifiée, champ quitté |
submit |
envoi d’un formulaire |
keydown / keyup |
touche pressée / relâchée |
Un module est simplement un fichier .ts qui exporte certains éléments et en importe d’autres.
import dit de quoi le fichier a besoinUne fonction non exportée correspond à une fonction static en C : l’isolement est la règle, l’exposition l’exception.
src/scripts/moduleMath.ts
src/scripts/app.ts
Le ./ n’est pas décoratif : sans lui, on cherche un paquet dans node_modules. La page ne charge que app.ts ; Astro suit la chaîne des import tout seul.
| Forme | Dans le module | Chez l’appelant |
|---|---|---|
| Nommé (recommandé) | export const pi = 3.14; |
import { pi } from "./m.ts"; |
| Par défaut | export default function f() {} |
import f from "./m.ts"; |
| Renommage | export const pi = 3.14; |
import { pi as PI } from "./m.ts"; |
| Global | (rien) | import * as M from "./m.ts"; puis M.pi |
asUn import déclare un nom dans votre fichier. Deux fois le même nom donne Duplicate identifier : le compilateur ne peut pas choisir à votre place.
C’est au fichier qui importe, le seul à voir les deux modules, de trancher.
Parcours essentiel, dans l’ordre
Ensuite
Tapez les exemples, ne les lisez pas. Les corrigés sont dépliables sous chaque énoncé : ouvrez-les après avoir essayé.