Les fonctions sont au cœur de nos programmes JavaScript. Mais sans garde-fous, elles peuvent vite devenir une source de bugs. C'est pourquoi utiliser TypeScript pour typer ses fonctions au maximum est si pratiqué de nos jours ; car bien les typer, c’est garantir un code plus sûr, plus lisible, et surtout, plus facile à maintenir !
Dans cet article, je vous propose donc de découvrir comment bien typer ses fonctions avec TypeScript, afin d'écrire du code à l'épreuve des bugs (du moins, au possible !). Nous verrons donc ensemble les bases du typage pour les fonctions, des options avancées comme void ou never, et des techniques pour gérer les cas tordus. J'en profiterai également pour vous glisser quelques astuces pratiques, qui sauront très certainement vous aider au quotidien (sauf si vous êtes déjà un pro de TS, bien entendu !). Alors, intéressé ? Si oui, bonne lecture à vous 🙂
Remarque : pour voir une application pratique de ces typages, je vous conseille d'aller ensuite faire un tour dans la rubrique "Projets", où vous trouverez tout un tas d'exemples concrets, vous montrant comment "bien" typer ses variables et fonctions, en TypeScript !
Salut ! Bienvenue sur LeCoinTS, où je partage des tutos TypeScript gratuits et sans pub. Envie de me soutenir dans cette aventure, avec un café ? ☕

Le typage des entrées/sortie d'une fonction (paramètres/retour)
En TypeScript, on peut typer ses fonctions à 2 niveaux :
- au niveau des paramètres d'entrée, passés en argument de la fonction, si y'en a
- au niveau des données retournées par une fonction, le cas échéant
Ainsi, on peut éviter tout un tas d'erreurs imprévues, dès le départ, en typant exactement ce qu'on est sensé transmettre ou recevoir d'une fonction ! Et c'est bien là tout l'intérêt de code en TypeScript !
Alors, histoire d'illustrer tout cela, voici un exemple de code TS simple, avec une fonction typée en entrée, comme en sortie :
function retourneTexteSuivantAge(age: number): string {
if (age < 18) return "Vous êtes mineur";
else if (age > 18) return "Vous êtes majeur";
else return "Vous avez pile 18 ans !";
}
console.log(retourneTexteSuivantAge(17)); // "Vous êtes mineur"
console.log(retourneTexteSuivantAge("Fannie")); // Argument of type 'string' is not assignable to parameter of type 'number'
Ici, on a bien typé l'entrée et la sortie de la fonction, avec :
age: number
en paramètre d'entrée, permettant la remontée d'erreur si jamais on envoie un autre type qu'une valeur numérique à cette fonction- et le
:string
après la fermeture de parenthèse, en sortie, permettant d'expliciter clairement le fait que cette fonction retournera une chaîne de caractère, et aucun autre type
Au passage, si votre éditeur est "bien configuré", cela devrait directement apparaître à l'écran (comme ci-dessous, avec VS Code) :

Comme nous avons bien typé notre fonction "retourneTexteSuivantAge", le problème apparaît clairement dans l'IDE (et c'est donc facile à corriger !). En effet, cette fonction s'attend à une valeur numérique en paramètre ; or, on lui envoie à moment donné une chaîne de caractères, "Fannie", ce qui est incohérent avec le typage que nous avons renseigné.
Du coup, mon conseil serait le suivant : typez toujours vos fonctions au maximum avec TypeScript, aussi bien en entrée, qu'en sortie ! D'ailleurs, cela vous aidera énormément par la suite, si vous travaillez sur des gros projets, en équipe !
Du reste, au delà de ça : si vous prévoyez de coder une fonction retournant un objet, n'hésitez pas à vous servir des "interfaces" pour caractériser le plus précisément possible le format de cet objet, retourné par la fonction. Ainsi, tout sera parfaitement cadré, permettant la remontée immédiate d'éventuelles erreurs 🙂
Les paramètres optionnels et valeurs par défaut, à l'appel d'une fonction
Parfois, un paramètre d'entrée d'une fonction peut être facultatif. Pour spécifier clairement cela, TS offre 2 façons de faire les choses :
- avec le symbole "?", pour indiquer qu'un paramètre est optionnel
- avec une valeur par défaut, pour indiquer qu'un paramètre est optionnel, mais avec une valeur par défaut qui lui est attribué, en cas d'absence
Dis comme ça, ça doit pas trop vous parler ! Alors je vais immédiatement vous mettre un exemple de chaque, afin que ce soit beaucoup plus parlant !
Les paramètres optionnels d'une fonction (en TypeScript)
Voici un exemple de code TS, avec un paramètre optionnel dans la fonction :
function presenter(prenom: string, age?: number): string {
return age ? `${prenom} a ${age} ans` : `${prenom} est là`;
}
console.log(presenter("Antoine")); // "Antoine est là"
console.log(presenter("Séverine", 30)); // "Séverine a 30 ans"
console.log(presenter(45)); // Argument of type 'number' is not assignable to parameter of type 'string'
Ici, le paramètre "age?", avec son point d'interrogation accolé, signifie que ce paramètre est optionnel. Ainsi, il n'est pas obligatoire de renseigner cette valeur, au moment de l'appel de la fonction "presenter".
Mais là où TypeScript devient intéressant, c'est qu'en typant les paramètres d'entrée correctement, on peut détecter un mélange de typage précocement (évitant ainsi les codes boiteux, qui continuent à s'exécuter malgré tout !). C'est d'ailleurs ce qu'on voit lorsque l'instruction console.log(presenter(45));
est appelée ; où là, on a transmit une variable numérique comme premier argument, à la place d'une chaîne de caractères. Merci TypeScript, de nous remonter cette erreur de codage 😉
Les paramètres par défaut d'une fonction (en TypeScript)
Et voici un exemple de code, avec un paramètre par défaut dans la fonction :
function saluer(prenom: string, message = "Salut à toi"): string {
return `${message}, ${prenom} !`;
}
console.log(saluer("Pierre")); // "Salut à toi, Pierre !"
console.log(saluer("Charline")); // "Salut à toi, Charline !"
console.log(saluer("Sandra", "Bonsoir")); // "Bonsoir, Sandra !"
console.log(saluer("Antoine", 32)); // Argument of type 'number' is not assignable to parameter of type 'string'
Ici, vous remarquez que la variable "message" contiendra toujours la chaîne de caractère "Salut à toi", si ce message n'est pas transmis à l'appel de la fonction.
Par ailleurs, implicitement, le paramètre "message" sera forcément et toujours de type "string", puis qu'il est initialisé par une chaîne de caractère (notre valeur par défaut "Salut à toi", en l'occurrence). Du coup, si vous envoyez par exemple un nombre entier, comme avec la ligne console.log(saluer("Antoine", 32));
, alors une erreur sera retournée (car le paramètre message doit être de type chaîne de caractère, et non de type valeur numérique).
Du reste, en synthèse :
- utilisez "?" lorsqu'un paramètre est vraiment optionnel
- utilisez des valeurs par défaut lorsque des valeurs implicites par défaut font sens
Les typages avancés : void et never (en sortie de fonction)
Il arrive parfois/souvent qu'une fonction ne doive rien retourner, ou ne doive jamais finir de s'exécuter. En TS, on a 2 mots clefs pour caractériser cela : void et never.
Les fonctions ne retournant rien (void)
Ici, on va explicitement déclarer qu'une fonction ne retournera rien, avec le mot clef "void". Et pour illustrer cela, voici un exemple de fonction typée avec "void" sur le retour :
function logMessage(texte: string): void {
console.log(texte); // Pas de return
}
logMessage("Bonjour à tous !"); // Affiche en console : "Bonjour à tous !"
Résultat de ce code : le message "Bonjour à tous !" s'affiche lorsque la fonction est appelée, mais cette dernière ne retourne strictement rien.
Comme toujours, l'idée dernière tout ça est de coder le plus proprement possible, pour limiter au maximum les erreurs de programmation, en amont ! Et lorsqu'on travaille en équipe, cela permet de cadrer les choses (en excluant tout "return" au niveau de la fonction, dans ce cas).
Vous aimez cet article ? LeCoinTS reste gratuit et sans pub grâce à vos dons.
Motivez-moi à en faire plus ! ☕

Les fonctions ne finissant jamais (never)
À présent, voyons le mot clef "never" ! Alors, avec celui ci, on précisera de manière explicite que notre fonction ne s'arrêtera jamais. J'ai en tête 2 exemples où l'on peut s'en servir : dans une fonction qui stoppe "brutalement" le programme (comme lorsqu'on génère une erreur, par exemple), et en cas de boucle while sans condition de sortie. Voici d'ailleurs ces deux exemples, codés en TS :
// Premier exemple avec "never"
function erreurFatale(message: string): never {
throw new Error(message); // Ne retourne jamais rien, car le programme va stopper ici, en générant une erreur
}
// Deuxième exemple avec "never"
function boucleInfinie(): never {
while (true) {}
}
Là encore, dites-vous bien que l'idée derrière l'usage des mots clef "void" et "never" est de cadrer les choses, pour éviter les imprévus au possible. Bien coder commence par là, même si c'est un peu "lourd" au début 😉
Les unions de types (en entrée ou sortie de fonction)
Lorsqu'une fonction accepte plusieurs types sur un paramètre donné, ou retourne des résultats variés (de plusieurs types possibles), les unions (|) sont nos amies ! Car cela permet de cadrer très précisément ce qui est admis en entrée, et/ou retournable en sortie d'une fonction. Ainsi, pas de risque d'erreur, du moins à ce niveau 🙂
Voici un exemple :
function convertirEnTexte(valeur: string | number): string {
return typeof valeur === "string" ? valeur : valeur.toString();
}
console.log(convertirEnTexte("texte simple")); // "test"
console.log(convertirEnTexte(42)); // "42"
console.log(convertirEnTexte("42")); // "42"
console.log(convertirEnTexte(true)); // Argument of type 'boolean' is not assignable
// to parameter of type 'string | number'
Ici on admet une fonction nommée "convertirEnTexte", qui accepte une valeur numérique ou une chaîne de caractères en entrée. Cette fonction retourne ce qui lui est envoyé, au format texte (le "string" étant déjà au format "string", elle n'a juste qu'à convertir les "number" en "string", au final !).
Le fait de spécifier tous les types acceptables sur le paramètre "valeur" permet de détecter toute erreur de typage à ce niveau, comme on peut le constater sur la dernière ligne de cet exemple, lors de la tentative de passage d'un booléen en argument de la fonction.
Fonctions fléchées et signatures explicites de fonction
Les fonctions fléchées sont devenues quelque chose de courant en JS. Et encore plus en TS, car on peut les typer de manière concise. Et encore encore plus, si je puis dire, avec des signatures détaillées ! Je m'explique… !
Voici un exemple de fonctions TypeScript simples, typées en entrée et en sortie :
const addition = (a: number, b: number): number => a + b;
const soustraction = (a: number, b: number): number => a - b;
const multiplication = (a: number, b: number): number => a * b;
const division = (a: number, b: number): number => a / b;
Ici, on a 4 opérations de base stockées dans des fonctions utilisables par la suite. Mais on peut faire mieux, en TypeScript. Voici ce que ça donne :
type Operation = (x: number, y: number) => number;
const addition: Operation = (a, b) => a + b;
const soustraction: Operation = (a, b) => a - b;
const multiplication: Operation = (a, b) => a * b;
const division: Operation = (a, b) => a / b;
En créant un nouveau type, nommé "Operation", on décrit les entrées / sortie des fonctions qui reposeront sur ce cadre. Ainsi, on les code de façon homogène, renforçant notre qualité de travail !
Bonus : un mix "union de types" + mot clef never, pour la gestion d'erreurs !
Histoire de faire un mix de tout ce que nous avons vu précédemment… ou presque (!), voici un exemple de fonction parfaitement bien typée :
function diviser(a: number, b: number): number | never {
if (b === 0) throw new Error("Division par zéro interdite !");
return a / b;
}
try {
console.log(diviser(10, 2)); // = 5
console.log(diviser(10, 0)); // = erreur levée, avec affichage du texte "Division par zéro interdite !"
console.log(diviser("10", "2")); // = signalement TypeScript : Argument of type 'string' is not assignable
} catch (e) { // to parameter of type 'number'
console.log(e);
}
Dans cet exemple :
- on a bien défini nos entrées de fonction, avec a et b de type "number". C'est pourquoi si on envoie une chaîne de caractère à la place, quand bien même celle-ci comporterait un nombre à l'intérieur, eh bien ça remonte logiquement une erreur de typage
- on a bien défini notre sortie de fonction, en spécifiant que le retour sera soit un nombre (number), soit rien du fait qu'on ne sortira jamais de cette fonction (never). Et ça colle exactement au comportement attendu de cette fonction, car si le dénominateur b de la division n'est pas égal à zéro, alors on retourne a/b ; autrement, on stoppe le programme immédiatement, avec un message d'erreur "division par zéro impossible" affiché sur la console
En synthèse, combiner never et des unions avec des blocs try/catch permet une gestion claire des exceptions, au niveau des fonctions ! Alors ne vous en privez pas, en codant !
Conclusion
Bien typer ses fonctions en TypeScript, c’est poser des garde-fous, qui vous garantiront un code plus sûr. Pour cela, il faut explicitement typer les paramètres d'entrée et les retours de fonction, et ne pas hésiter à utiliser les mots clefs "void" ou "never", pour gérer les cas spéciaux.
Plus généralement, en synthèse, voici quelques "règles de conduite" qui pourraient bien résumer cet article :
- Codez avec clarté : toujours typer les entrées (paramètres) et sortie (retour) de vos fonctions
- Éliminez les imprévus : c'est vrai que je ne l'ai pas précisé ici, mais évitez d'utiliser le type "any", au possible, sinon vous enlèverez tout l'intérêt de TypeScript
- Typez de manière exhaustive : utilisez never dans vos fonctions avec gestion d'erreur ou boucles infinies, et void quand elles ne retournent tout simplement rien
- Codez avec lisibilité : préférez des noms de paramètres explicites et des signatures séparées pour les fonctions complexes (comme le type "Operation" que nous avons vu plus haut)
Voilà, je crois qu'on a fait le tour de la question ! Alors je vous laisse, et vous souhaite un bon codage ! Et pour ceux qui voudraient soutenir le site, un café est toujours le bienvenue ! (cf. bouton jaune ci-dessous)
Merci d’avoir lu cet article ! LeCoinTS reste gratuit et sans pub grâce à vous.
Un petit don pour soutenir le site ? ☕


JEROME
Passionné par tout ce qui touche à la programmation informatique en TypeScript, sans toutefois en être expert, j'ai à coeur de vous partager ici, peu à peu, tout ce que j'ai appris, découvert, réalisé, et testé jusqu'à présent ! En espérant que tout cela puisse vous servir, ainsi qu'au plus grand nombre de francophones possible !
(*) Mis à jour le 14/04/2025