3. Les bases de TypeScript
Note : dans la suite, le terme [TypeScript] désignera le langage tel que défini par sa version 6, superset typé d'ECMAScript 2026.
Les scripts de ce chapitre se trouvent dans le dossier [bases] du projet.
3.1. script [bases-01]
Ce script reprend l'exemple introductif du cours JavaScript original, traduit et typé en TypeScript :
| /* eslint-disable no-constant-condition */
'use strict';
// ceci est un commentaire
// constante
const nom: string = "dupont";
// un affichage écran
console.log("nom : ", nom);
// un tableau avec des éléments de type différent
// [any] car ce tableau mélange volontairement plusieurs types (démonstration)
const tableau: any[] = ["un", "deux", 3, 4];
// son nombre d'éléments
let n: any = tableau.length;
// une boucle
for (let i = 0; i < n; i++) {
console.log("tableau[", i, "] = ", tableau[i]);
}
// initialisation de 2 variables avec le contenu d'un tableau
let [chaine1, chaine2]: string[] = ["chaine1", "chaine2"];
// concaténation des 2 chaînes
const chaine3 = chaine1 + chaine2;
// affichage résultat
console.log([chaine1, chaine2, chaine3]);
// utilisation fonction
affiche(chaine1);
// le type d'une variable peut être connu
afficheType("n", n);
afficheType("chaine1", chaine1);
afficheType("tableau", tableau);
// le type d'une variable peut changer en cours d'exécution
// [n] est typé [any] plus haut : c'est justement ce qui permet à TypeScript
// d'accepter cette réaffectation en cours de route, comme en JavaScript
n = "a changé";
afficheType("n", n);
// une fonction peut rendre un résultat
let res1: any = f1(4);
console.log("res1=", res1);
// une fonction peut rendre un tableau de valeurs
let res2: any, res3: any;
[res1, res2, res3] = f2();
console.log("(res1,res2,res3)=", [res1, res2, res3]);
// on aurait pu récupérer ces valeurs dans un tableau
let t: any[] = f2();
for (let i = 0; i < t.length; i++) {
console.log("t[", i, "]=", t[i]);
}
// des tests
for (let i = 0; i < t.length; i++) {
// n'affiche que les chaînes
if (typeof (t[i]) === "string") {
console.log("t[", i, "]=", t[i]);
}
}
// opérateurs de comparaison == et ===
if ("2" == (2 as any)) {
console.log("avec l'opérateur ==, la chaîne 2 est égale à l'entier 2");
} else {
console.log("avec l'opérateur ==, la chaîne 2 n'est pas égale à l'entier 2");
}
if (("2" as any) === 2) {
console.log("avec l'opérateur ===, la chaîne 2 est égale à l'entier 2");
} else {
console.log("avec l'opérateur ===, la chaîne 2 n'est pas égale à l'entier 2");
}
// d'autres tests
for (let i = 0; i < t.length; i++) {
// n'affiche que les entiers >10
if (typeof (t[i]) === "number" && Math.floor(t[i]) === t[i] && t[i] > 10) {
console.log("t[", i, "]=", t[i]);
}
}
// une boucle while
t = [8, 5, 0, -2, 3, 4];
let i = 0;
let somme = 0;
while (i < t.length && t[i] > 0) {
console.log("t[", i, "]=", t[i]);
somme += t[i];
i++;
}
console.log("somme=", somme);
// arrêt du programme car il n'y a plus de code exécutable
//affiche
//----------------------------------
function affiche(chaine: string): void {
// affiche chaine
console.log("chaine=", chaine);
}
//afficheType
//----------------------------------
function afficheType(name: string, variable: unknown): void {
// affiche le type de variable
console.log("type[variable ", name, "]=", typeof (variable));
}
//----------------------------------
function f1(param: number): number {
// ajoute 10 à param
return param + 10;
}
//----------------------------------
function f2(): any[] {
// rend 3 valeurs
return ["un", 0, 100];
}
|
Commentons ce code :
- ligne 5 : [const nom: string = "dupont"] — en TypeScript, on peut annoter explicitement le type d'une variable avec : type après son nom. Ici, nom est garanti être une chaîne tout au long du programme ;
- ligne 10 : [const tableau: any[] = ...] — ce tableau mélange volontairement des chaînes et des nombres. Le type any[] indique à TypeScript de ne pas vérifier le type des éléments : c'est un choix explicite, différent d'un oubli de typage (que le mode strict interdit) ;
- ligne 12 : [let n: any = tableau.length] — n est typé any car, plus loin (ligne 32), on lui réaffecte une chaîne de caractères après lui avoir affecté un nombre. En JavaScript, une variable peut changer de type librement ; en TypeScript, ceci n'est permis que si on l'a explicitement autorisé avec any (ou une union de types, comme number | string) ;
- ligne 54 : ["2" == (2 as any)] — TypeScript interdit par défaut de comparer avec deux valeurs de types incompatibles (chaîne et nombre). L'expression (2 as any) est un transtypage (*type assertion*) : on dit explicitement à TypeScript « traite cette valeur comme any, ne vérifie pas son type ici », ce qui permet de illustrer volontairement la coercion de type propre à l'opérateur ;
- ligne 93 : la fonction [function afficheType(name: string, variable: unknown): void] type son second paramètre unknown plutôt que any. Contrairement à any, unknown interdit d'utiliser la valeur sans l'avoir d'abord vérifiée — ici, on se contente de typeof(variable), ce qui est autorisé même sur unknown ;
- lignes 86-108 : les fonctions ont désormais un type de retour explicite (: number, : void...), écrit après la liste de paramètres.
Exécutons ce script :
npx tsx bases/bases-01.ts
Résultat de l'exécution :
| nom : dupont
tableau[ 0 ] = un
tableau[ 1 ] = deux
tableau[ 2 ] = 3
tableau[ 3 ] = 4
[ 'chaine1', 'chaine2', 'chaine1chaine2' ]
chaine= chaine1
type[variable n ]= number
type[variable chaine1 ]= string
type[variable tableau ]= object
type[variable n ]= string
res1= 14
(res1,res2,res3)= [ 'un', 0, 100 ]
t[ 0 ]= un
t[ 1 ]= 0
t[ 2 ]= 100
t[ 0 ]= un
avec l'opérateur ==, la chaîne 2 est égale à l'entier 2
avec l'opérateur ===, la chaîne 2 n'est pas égale à l'entier 2
t[ 2 ]= 100
t[ 0 ]= 8
t[ 1 ]= 5
somme= 13
|
3.2. script [bases-02]
Le script [bases-02] montre l'utilisation des mots clés [let] et [const] :
| 'use strict';
// pour initialiser une variable, on utilise let ou const
// let pour les variables
let x: number = 4;
x++;
console.log(x);
// const pour les constantes
const y: number = 10;
x += y;
// interdit
y++;
|
- [let] déclare une variable dont la valeur peut changer (lignes 4-5) ;
- [const] déclare une constante dont la valeur ne peut pas changer (ligne 8) ;
- ligne 11 : on tente de réaffecter la constante y avec y++. C'est ici que TypeScript apporte un vrai plus par rapport à JavaScript.
Avant même d'exécuter le script, la vérification de types signale l'erreur :
Résultat de l'exécution :
| bases/bases-02.ts(11,1): error TS2588: Cannot assign to 'y' because it is a constant.
|
En JavaScript pur, cette même erreur n'aurait été détectée qu'à l'exécution. Exécutons malgré tout ce script avec tsx (qui exécute le code sans vérifier les types au préalable, contrairement à tsc) pour voir l'erreur telle que JavaScript la lève réellement :
npx tsx bases/bases-02.ts
Résultat de l'exécution :
| 5
TypeError: Assignment to constant variable.
at bases/bases-02.ts:11:1
|
Important : tsx transpile le TypeScript en JavaScript sans vérification de types (comme le fait Babel), pour une exécution rapide pendant le développement. C'est pourquoi ce script s'exécute (et plante à l'exécution) même s'il ne compile pas avec tsc. Pour être averti de l'erreur avant l'exécution, on se fie à VSCode (qui utilise tsc en tâche de fond) ou à la commande npm run check.
3.3. script [bases-03]
Illustre la portée des variables globales, visibles à l'intérieur d'une fonction :
| 'use strict';
// portée des variables
let count: number = 1;
function doSomething(): void {
// count est ici connu
console.log("count=", count);
}
// appel
doSomething();
|
npx tsx bases/bases-03.ts
Résultat de l'exécution :
3.4. script [bases-04]
Une variable locale à une fonction cache (masque) une variable globale de même nom :
| 'use strict';
// portée des variables
const count: number = 1;
function doSomething(): void {
// la variable locale cache la variable globale
const count = 2;
console.log("count inside function=", count);
}
// variable globale
console.log("count outside function=", count);
// variable locale
doSomething();
|
npx tsx bases/bases-04.ts
Résultat de l'exécution :
| count outside function= 1
count inside function= 2
|
3.5. script [bases-05]
Une variable locale (const count à l'intérieur de la fonction) n'est pas visible en dehors de cette fonction :
| 'use strict';
// portée des variables
function doSomething(): void {
// variable locale à la fonction
const count = 2;
console.log("count inside function=", count);
}
// ici count n'est pas connu
console.log("count outside function=", count);
doSomething();
|
Ici encore, TypeScript détecte le problème dès la compilation — pas besoin d'exécuter le script pour le savoir :
Résultat de l'exécution :
| bases/bases-05.ts(9,40): error TS2304: Cannot find name 'count'.
|
Et à l'exécution avec tsx :
npx tsx bases/bases-05.ts
Résultat de l'exécution :
| ReferenceError: count is not defined
at bases/bases-05.ts:9:40
|
3.6. script [bases-06]
Ce script compare la portée de bloc ([let], [const]) à l'absence de portée de bloc ([var]) :
| 'use strict';
// le mot clé [let] permet de définir une variable de portée bloc
{
// la variable [count] n'est connue que dans ce bloc
let count: number = 1;
console.log("count=", count);
}
// ici la variable [count] n'est pas connue
count++;
// le mot clé [const] permet de définir une variable de portée bloc
{
// la variable [count2] n'est connue que dans ce bloc
const count2: number = 1;
console.log("count=", count2);
}
// ici la variable [count2] n'est pas connue
count2++;
// le mot clé [var] ne permet pas de définir une variable de portée bloc
{
// la variable [count3] sera connue globalement
var count3: number = 1;
console.log("count=", count3);
}
// ici la variable [count3] est connue
count3++;
|
- une variable déclarée avec [let] ou [const] à l'intérieur d'un bloc { } n'existe que dans ce bloc ;
- une variable déclarée avec [var] ignore les blocs : elle reste visible dans toute la fonction (ou tout le script) qui l'entoure — c'était le seul comportement disponible avant ECMAScript 2015, source de bien des bugs, d'où la recommandation de toujours préférer [let]/[const].
Compilation :
Résultat de l'exécution :
| bases/bases-06.ts(9,1): error TS2552: Cannot find name 'count'. Did you mean 'count3'?
bases/bases-06.ts(18,1): error TS2552: Cannot find name 'count2'. Did you mean 'count3'?
|
Exécution (le script s'arrête à la première erreur rencontrée, sur count) :
npx tsx bases/bases-06.ts
Résultat de l'exécution :
| count= 1
ReferenceError: count is not defined
at bases/bases-06.ts:9:1
|
3.7. script [bases-07]
Panorama des principaux types TypeScript :
| 'use strict';
// type de données jS
const var1: number = 10;
const var2: string = "abc";
const var3: boolean = true;
const var4: number[] = [1, 2, 3];
const var5: { nom: string } = {
nom: 'axèle'
};
const var6: () => number = function () {
return +3;
}
// affichage des types
console.log("typeof(var1)=", typeof (var1));
console.log("typeof(var2)=", typeof (var2));
console.log("typeof(var3)=", typeof (var3));
console.log("typeof(var4)=", typeof (var4));
console.log("typeof(var5)=", typeof (var5));
console.log("typeof(var6)=", typeof (var6));
|
- [var5: { nom: string }] — un type objet inline : on décrit directement, entre accolades, la forme attendue de l'objet, sans avoir à déclarer une interface séparée ;
- [var6: () => number] — le type d'une fonction : une fonction sans paramètre, qui rend un number ;
- à l'exécution, typeof reste celui de JavaScript (il ignore les annotations de type, qui n'existent qu'à la compilation et disparaissent ensuite) : c'est pourquoi typeof(var4) (un tableau) et typeof(var5) (un objet) rendent tous deux "object".
npx tsx bases/bases-07.ts
Résultat de l'exécution :
| typeof(var1)= number
typeof(var2)= string
typeof(var3)= boolean
typeof(var4)= object
typeof(var5)= object
typeof(var6)= function
|
3.8. script [bases-08]
Les conversions de type, implicites et explicites, restent celles de JavaScript (TypeScript ne change rien à l'exécution) :
| 'use strict';
// changements implicites de types
// type -->bool
console.log("---------------[Conversion implicite vers un booléen]------------------------------");
showBool("abcd");
showBool("");
showBool([1, 2, 3]);
showBool([]);
showBool(null);
showBool(0.0);
showBool(0);
showBool(4.6);
showBool({});
showBool(undefined);
// [any] car cette fonction accepte volontairement n'importe quel type en entrée
function showBool(data: any): void {
// la conversion de data en booléen se fait automatiquement dans le test qui suit
console.log("[data=", data, "], [type(data)]=", typeof (data), "[valeur booléenne(data)]=", data ? true : false);
}
// changements implicites de type vers un type numérique
console.log("---------------[Conversion implicite vers un nombre]------------------------------");
showNumber("12");
showNumber("45.67");
showNumber("abcd");
function showNumber(data: any): void {
// data + 1 ne marche pas car alors jS fait une concaténation de chaînes plutôt qu'une addition
const nombre = data * 1;
console.log("[data=", data, "], [type(data)]=", typeof (data), "[nombre]=", nombre, "[type(nombre)]=", typeof (nombre));
}
// changements explicites de types vers un booléen
console.log("---------------[Conversion explicite vers un booléen]------------------------------");
showBool2("abcd");
showBool2("");
showBool2([1, 2, 3]);
showBool2([]);
showBool2(null);
showBool2(0.0);
showBool2(0);
showBool2(4.6);
showBool2({});
showBool2(undefined);
function showBool2(data: any): void {
// la conversion de data en booléen se fait explicitement dans le test qui suit
console.log("[", data, "], [type(data)]=", typeof (data), "[valeur booléenne(data)]=", Boolean(data));
}
// changements explicites de type vers Number
console.log("---------------[Conversion explicite vers un nombre]------------------------------");
showNumber2("12.45");
showNumber2(67.8);
showNumber2(true);
showNumber2(null);
function showNumber2(data: any): void {
const nombre = Number(data);
console.log("[data=", data, "], [type(data)]=", typeof (data), "[nombre]=", nombre, "[type(nombre)]=", typeof (nombre));
}
// vers String
console.log("---------------[Conversion explicite vers un string]------------------------------");
showString(5);
showString(6.7);
showString(false);
showString(null);
function showString(data: any): void {
const chaîne = String(data);
console.log("[data=", data, "], [type(data)]=", typeof (data), "[chaîne]=", chaîne, "[type(chaîne)]=", typeof (chaîne));
}
// qqs conversions implicites inattendues
console.log("---------------[Autres cas]------------------------------");
const string1: string = '1000.78';
// concaténation de chaînes par défaut
const data1 = string1 + 1.034;
console.log("data1=", data1, "type=", typeof (data1));
const data2 = 1.034 + string1;
console.log("data2=", data2, "type=", typeof (data2));
// conversion explicite vers nombre
const data3 = Number(string1) + 1.034;
console.log("data3=", data3, "type=", typeof (data3));
// true est converti en le nombre 1
const data4 = (true as any) * 1.18;
console.log("data4=", data4, "type=", typeof (data4));
// false est converti en le nombre 0
const data5 = (false as any) * 1.18;
console.log("data5=", data5, "type=", typeof (data5));
|
- toutes les fonctions de ce script typent leur paramètre data: any : c'est volontaire, puisque le but est justement de montrer comment une même fonction se comporte avec des valeurs de types très différents (chaîne, tableau, null, undefined...) ;
- [Boolean(data)], [Number(data)], [String(data)] sont les conversions explicites — toujours préférables aux conversions implicites, plus prévisibles et plus lisibles ;
- dernier bloc : string1 + 1.034 donne une concaténation de chaînes (le + avec une chaîne à gauche ou à droite privilégie la concaténation), tandis que Number(string1) + 1.034 donne une addition numérique.
npx tsx bases/bases-08.ts
Résultat de l'exécution :
| ---------------[Conversion implicite vers un booléen]------------------------------
[data= abcd ], [type(data)]= string [valeur booléenne(data)]= true
[data= ], [type(data)]= string [valeur booléenne(data)]= false
[data= [ 1, 2, 3 ] ], [type(data)]= object [valeur booléenne(data)]= true
[data= [] ], [type(data)]= object [valeur booléenne(data)]= true
[data= null ], [type(data)]= object [valeur booléenne(data)]= false
[data= 0 ], [type(data)]= number [valeur booléenne(data)]= false
[data= 0 ], [type(data)]= number [valeur booléenne(data)]= false
[data= 4.6 ], [type(data)]= number [valeur booléenne(data)]= true
[data= {} ], [type(data)]= object [valeur booléenne(data)]= true
[data= undefined ], [type(data)]= undefined [valeur booléenne(data)]= false
---------------[Conversion implicite vers un nombre]------------------------------
[data= 12 ], [type(data)]= string [nombre]= 12 [type(nombre)]= number
[data= 45.67 ], [type(data)]= string [nombre]= 45.67 [type(nombre)]= number
[data= abcd ], [type(data)]= string [nombre]= NaN [type(nombre)]= number
---------------[Conversion explicite vers un booléen]------------------------------
[ abcd ], [type(data)]= string [valeur booléenne(data)]= true
[ ], [type(data)]= string [valeur booléenne(data)]= false
[ [ 1, 2, 3 ] ], [type(data)]= object [valeur booléenne(data)]= true
[ [] ], [type(data)]= object [valeur booléenne(data)]= true
[ null ], [type(data)]= object [valeur booléenne(data)]= false
[ 0 ], [type(data)]= number [valeur booléenne(data)]= false
[ 0 ], [type(data)]= number [valeur booléenne(data)]= false
[ 4.6 ], [type(data)]= number [valeur booléenne(data)]= true
[ {} ], [type(data)]= object [valeur booléenne(data)]= true
[ undefined ], [type(data)]= undefined [valeur booléenne(data)]= false
---------------[Conversion explicite vers un nombre]------------------------------
[data= 12.45 ], [type(data)]= string [nombre]= 12.45 [type(nombre)]= number
[data= 67.8 ], [type(data)]= number [nombre]= 67.8 [type(nombre)]= number
[data= true ], [type(data)]= boolean [nombre]= 1 [type(nombre)]= number
[data= null ], [type(data)]= object [nombre]= 0 [type(nombre)]= number
---------------[Conversion explicite vers un string]------------------------------
[data= 5 ], [type(data)]= number [chaîne]= 5 [type(chaîne)]= string
[data= 6.7 ], [type(data)]= number [chaîne]= 6.7 [type(chaîne)]= string
[data= false ], [type(data)]= boolean [chaîne]= false [type(chaîne)]= string
[data= null ], [type(data)]= object [chaîne]= null [type(chaîne)]= string
---------------[Autres cas]------------------------------
data1= 1000.781.034 type= string
data2= 1.0341000.78 type= string
data3= 1001.814 type= number
data4= 1.18 type= number
data5= 0 type= number
|
3.9. script [bases-09]
[NOUVEAU depuis 2019] Ce script présente des opérateurs apparus dans ECMAScript 2020-2021, aujourd'hui très couramment utilisés :
| 'use strict';
// ========================================================================
// [NOUVEAU depuis 2019] quelques opérateurs modernes très utilisés au quotidien
// ========================================================================
// ------------------------------------------------------------------------
// 1) l'opérateur de coalescence des nuls [??] (ECMAScript 2020)
// ------------------------------------------------------------------------
// avec [||], une valeur "fausse" (0, "", false, NaN, ...) déclenche la valeur par défaut,
// ce qui n'est pas toujours ce qu'on veut
const quantité1: number = 0;
console.log("avec || : quantité1 || 10 =", quantité1 || 10); // -> 10 (bug ! 0 est pourtant une quantité valide)
// [??] ne déclenche la valeur par défaut que si la valeur est null ou undefined
console.log("avec ?? : quantité1 ?? 10 =", quantité1 ?? 10); // -> 0 (correct)
const quantité2: number | null = null;
console.log("quantité2 ?? 10 =", quantité2 ?? 10); // -> 10 (quantité2 est null)
const quantité3: number | undefined = undefined;
console.log("quantité3 ?? 10 =", quantité3 ?? 10); // -> 10 (quantité3 est undefined)
// ------------------------------------------------------------------------
// 2) le chaînage optionnel [?.] (ECMAScript 2020)
// ------------------------------------------------------------------------
// avant 2020, pour accéder en sécurité à une propriété profonde, il fallait
// tester chaque niveau : if (personne && personne.adresse && personne.adresse.ville) ...
// interface commune : [adresse] est optionnelle (personne2 n'en a pas)
interface PersonneAvecAdresseOptionnelle {
nom: string;
adresse?: { ville: string };
}
const personne1: PersonneAvecAdresseOptionnelle = {
nom: "Dupont",
adresse: {
ville: "Nantes"
}
};
const personne2: PersonneAvecAdresseOptionnelle = {
nom: "Martin"
// pas d'adresse !
};
// [?.] arrête l'évaluation et rend [undefined] dès qu'une étape est null ou undefined
// au lieu de lancer une erreur "Cannot read properties of undefined"
console.log("personne1 ville =", personne1.adresse?.ville);
console.log("personne2 ville =", personne2.adresse?.ville); // -> undefined, pas d'erreur
// on peut combiner [?.] et [??] pour fournir une valeur de remplacement
console.log("personne2 ville (avec défaut) =", personne2.adresse?.ville ?? "ville inconnue");
// [?.] fonctionne aussi sur les appels de méthode...
interface ObjetAvecMéthode {
direBonjour(): string;
direAurevoir?(): string;
}
const objetAvecMéthode: ObjetAvecMéthode = {
direBonjour() {
return "bonjour !";
}
};
console.log("appel méthode existante :", objetAvecMéthode.direBonjour?.());
console.log("appel méthode absente :", objetAvecMéthode.direAurevoir?.()); // -> undefined, pas d'erreur
// ...et sur l'accès à un élément de tableau
const tableauOuNull: number[] | null = null;
console.log("élément d'un tableau absent :", tableauOuNull?.[0]); // -> undefined
// ------------------------------------------------------------------------
// 3) les opérateurs d'affectation logique [||=], [&&=], [??=] (ECMAScript 2021)
// ------------------------------------------------------------------------
// ces opérateurs combinent un test logique et une affectation, en une seule écriture
// [a ??= b] équivaut à [a = a ?? b] : affecte b seulement si a est null/undefined
interface Configuration {
délai: number;
page?: number;
}
const config: Configuration = { délai: 0, page: undefined };
config.délai ??= 1000; // délai vaut déjà 0 (valeur valide) -> reste inchangé
config.page ??= 1; // page est undefined -> devient 1
console.log("config après ??= :", config);
// [a ||= b] équivaut à [a = a || b] : affecte b si a est "faux" (0, "", null, undefined, false...)
let messageAffiché: string = "";
messageAffiché ||= "message par défaut";
console.log("messageAffiché après ||= :", messageAffiché);
// [a &&= b] équivaut à [a = a && b] : affecte b seulement si a est déjà "vrai"
interface UtilisateurConnecté {
nom: string;
connecté?: boolean;
}
let utilisateurConnecté: UtilisateurConnecté | null = { nom: "Ana" };
utilisateurConnecté &&= { ...utilisateurConnecté, connecté: true };
console.log("utilisateurConnecté après &&= :", utilisateurConnecté);
// ------------------------------------------------------------------------
// 4) séparateurs numériques [_] (ECMAScript 2021)
// ------------------------------------------------------------------------
// purement visuel : rend les grands nombres plus lisibles dans le code source
const unMillion: number = 1_000_000;
const carteBancaire: bigint = 1234_5678_9012_3456n; // ici combiné avec un BigInt (voir plus bas)
console.log("unMillion =", unMillion);
console.log("carteBancaire =", carteBancaire);
// ------------------------------------------------------------------------
// 5) le type [BigInt] (ECMAScript 2020)
// ------------------------------------------------------------------------
// le type [number] de JavaScript perd sa précision au-delà de 2^53 environ
console.log("Number.MAX_SAFE_INTEGER =", Number.MAX_SAFE_INTEGER);
console.log("Number.MAX_SAFE_INTEGER + 1 =", Number.MAX_SAFE_INTEGER + 1);
console.log("Number.MAX_SAFE_INTEGER + 2 =", Number.MAX_SAFE_INTEGER + 2); // -> même résultat que +1, imprécis !
// un [BigInt] se note avec un [n] final, ou se construit avec BigInt(...)
const grandNombre1: bigint = 9007199254740993n;
const grandNombre2: bigint = BigInt("9007199254740993");
console.log("grandNombre1 =", grandNombre1, ", type =", typeof (grandNombre1));
console.log("grandNombre1 === grandNombre2 :", grandNombre1 === grandNombre2);
// un BigInt et un number ne peuvent pas être mélangés directement dans un calcul
try {
console.log((grandNombre1 as any) + 1); // provoque une erreur [TypeError]
} catch (error: any) {
console.log("erreur attendue :", error.message);
}
// il faut convertir explicitement
console.log("grandNombre1 + 1n =", grandNombre1 + 1n);
|
Commentons les nouveautés les plus importantes :
- [??], la coalescence des nuls (ECMAScript 2020) : contrairement à [||], qui déclenche sa valeur par défaut pour toute valeur « fausse » (0, "", false...), [??] ne se déclenche que si la valeur est null ou undefined. C'est le bon choix pour une quantité qui peut légitimement valoir 0 ;
- [?.], le chaînage optionnel (ECMAScript 2020) : arrête l'évaluation et rend undefined dès qu'une étape intermédiaire est null/undefined, au lieu de lancer une erreur. Fonctionne aussi sur les appels de méthode (objet.méthode?.()) et sur l'indexation (tableau?.[0]) ;
- [||=], [&&=], [??=], les opérateurs d'affectation logique (ECMAScript 2021) : combinent un test logique et une affectation en une seule écriture (a ??= b équivaut à a = a ?? b) ;
- les séparateurs numériques 1_000_000 (ECMAScript 2021) : purement visuels, ils rendent les grands nombres plus lisibles dans le code source ;
- le type [BigInt] (ECMAScript 2020), noté avec un n final (9007199254740993n) : contrairement à number, il ne perd pas de précision au-delà de Number.MAX_SAFE_INTEGER. Un BigInt et un number ne peuvent pas être mélangés directement dans un calcul, comme le montre le try/catch du script.
npx tsx bases/bases-09.ts
Résultat de l'exécution :
| avec || : quantité1 || 10 = 10
avec ?? : quantité1 ?? 10 = 0
quantité2 ?? 10 = 10
quantité3 ?? 10 = 10
personne1 ville = Nantes
personne2 ville = undefined
personne2 ville (avec défaut) = ville inconnue
appel méthode existante : bonjour !
appel méthode absente : undefined
élément d'un tableau absent : undefined
config après ??= : { 'délai': 0, page: 1 }
messageAffiché après ||= : message par défaut
utilisateurConnecté après &&= : { nom: 'Ana', 'connecté': true }
unMillion = 1000000
carteBancaire = 1234567890123456n
Number.MAX_SAFE_INTEGER = 9007199254740991
Number.MAX_SAFE_INTEGER + 1 = 9007199254740992
Number.MAX_SAFE_INTEGER + 2 = 9007199254740992
grandNombre1 = 9007199254740993n , type = bigint
grandNombre1 === grandNombre2 : true
erreur attendue : Cannot mix BigInt and other types, use explicit conversions
grandNombre1 + 1n = 9007199254740994n
|
3.10. Conclusion
Nous avons vu les bases du typage TypeScript : annotations de type sur les variables, paramètres et valeurs de retour de fonctions, les types any et unknown, ainsi que les principaux opérateurs modernes du langage (??, ?., ||=/&&=/??=) et le type BigInt. Le chapitre suivant aborde les tableaux.