Typage statique dynamique dans TypeScript
JavaScript est un langage de programmation intrinsèquement dynamique. En tant que développeurs, nous pouvons exprimer beaucoup de choses avec peu d'efforts, et le langage et son exécution déterminent ce que nous avions l'intention de faire. C'est ce qui rend JavaScript si populaire pour les débutants et qui rend les développeurs expérimentés productifs! Il y a cependant une mise en garde: nous devons être vigilants! Erreurs, fautes de frappe, comportement correct du programme: une grande partie de cela se produit dans nos têtes!
Jetez un œil à l'exemple suivant.
app.get ("/ api / users /: userID", function (req, res ) {
if (req.method === "POST") {
res.status (20) .send ({
message: "Got you, user" + req.params.userId
});
}
})
Nous avons un serveur de style https://expressjs.com/ qui nous permet de définir une route (ou un chemin), et exécute un rappel si l'URL est demandée.
Le rappel prend deux arguments:
- L'objet
request
.
Ici, nous obtenons des informations sur la méthode HTTP utilisée (par exemple GET, POST, PUT, DELETE) et des paramètres supplémentaires qui Dans cet exemple,userID
doit être mappé à un paramètreuserID
qui contient bien l'ID de l'utilisateur! - La réponse
réponse
objet.
Ici, nous voulons préparer une réponse appropriée du serveur au client. Nous voulons envoyer des codes d'état corrects (méthodestatus
) et envoyer la sortie JSON sur le fil.
Ce que nous voyons dans cet exemple est fortement simplifié, mais donne une bonne idée de ce que nous faisons. L'exemple ci-dessus est également truffé d'erreurs! Jetez un oeil:
app.get ("/ api / users /: userID", function (req, res) {
if (req.method === "POST") {/ * Erreur 1 * /
res.status (20) .send ({/ * Erreur 2 * /
message: "Bienvenue, utilisateur" + req.params.userId / * Erreur 3 * /
});
}
})
Oh wow! Trois lignes de code d'implémentation et trois erreurs? Que s'est-il passé?
- La première erreur est nuancée. Alors que nous disons à notre application que nous voulons écouter les requêtes GET (d'où
app.get
), nous ne faisons quelque chose que si la méthode de requête est POST . À ce stade particulier de notre application,req.method
ne peut pas être POST . Nous n'enverrions donc jamais de réponse, ce qui pourrait entraîner des délais inattendus. - Super que nous envoyions explicitement un code d'état!
20
n'est cependant pas un code d'état valide. Les clients peuvent ne pas comprendre ce qui se passe ici. - C'est la réponse que nous voulons renvoyer. Nous accédons aux arguments analysés mais avons une faute de frappe moyenne. Il s’agit de
userID
et non deuserId
. Tous nos utilisateurs seraient accueillis par "Bienvenue, utilisateur non défini!". Quelque chose que vous avez certainement vu dans la nature!
Et des choses comme ça arrivent! Surtout en JavaScript. Nous gagnons en expressivité – pas une seule fois, nous n'avons eu à nous soucier des types – mais devons faire très attention à ce que nous faisons.
C'est aussi là que JavaScript reçoit beaucoup de réactions négatives de la part de programmeurs qui ne sont pas habitués à la programmation dynamique langues. Ils ont généralement des compilateurs qui les signalent des problèmes possibles et détectent les erreurs à l'avance. Ils peuvent sembler arrogants quand ils froncent les sourcils sur la quantité de travail supplémentaire que vous devez faire dans votre tête pour s'assurer que tout fonctionne correctement. Ils pourraient même vous dire que JavaScript n'a aucun type. Ce qui n’est pas vrai.
Anders Hejlsberg, l’architecte principal de TypeScript, a déclaré dans son discours d’introduction MS Build 2017 que « ce n’est pas que JavaScript n’a pas de système de type. Il n’existe aucun moyen de le formaliser ».
Et c’est le but principal de TypeScript. TypeScript veut mieux comprendre votre code JavaScript que vous. Et là où TypeScript ne peut pas comprendre ce que vous voulez dire, vous pouvez vous aider en fournissant des informations de type supplémentaires.
Typage de base
Et c'est ce que nous allons faire maintenant. Prenons la méthode get
de notre serveur de style Express et ajoutons suffisamment d’informations de type pour que nous puissions exclure autant de catégories d’erreurs que possible.
Nous commençons par quelques informations de type de base. Nous avons un objet app
qui pointe vers une fonction get
. La fonction get
prend le chemin
qui est une chaîne, et un rappel.
const app = {
obtenir, / * publier, mettre, supprimer, ... à venir! * /
};
function get (chemin: chaîne, rappel: CallbackFn) {
// à mettre en œuvre -> pas important pour le moment
}
Alors que string
est un type de base, dit primitif CallbackFn
est un type composé que nous devons définir explicitement .
CallbackFn
est un type de fonction qui prend deux arguments:
req
qui est de typeServerRequest
-
reply
qui est du typeServerReply
CallbackFn
renvoie void
.
type CallbackFn = (req: ServerRequest, reply: ServerReply) => void;
ServerRequest
est un objet assez complexe dans la plupart des frameworks. Nous faisons une version simplifiée à des fins de démonstration. Nous passons dans une chaîne method
pour "GET"
"POST"
"PUT"
"DELETE"
etc. Il a également un enregistrement params
. Les enregistrements sont des objets qui associent un ensemble de clés à un ensemble de propriétés. Pour l'instant, nous voulons permettre à chaque clé string
d'être mappée à une propriété string
. Nous refactoriserons celui-ci plus tard.
type ServerRequest = {
méthode: chaîne;
paramètres: Record ;
};
Pour ServerReply
nous présentons quelques fonctions, sachant qu'un véritable objet ServerReply
a beaucoup plus. Une fonction send
prend un argument optionnel avec les données que nous voulons envoyer. Et nous avons la possibilité de définir un code d'état avec la fonction status
.
type ServerReply = {
envoyer: (obj ?: any) => void;
status: (statusCode: number) => ServerReply;
};
C'est déjà quelque chose, et nous pouvons écarter quelques erreurs:
app.get ("/ api / users /: userID", function (req, res) {
if (req.method === 2) {
// ^^^^^^^^^^^^^^^^^ 💥 Erreur, le numéro de type n'est pas attribuable à la chaîne
res.status ("200"). send ()
// ^^^^^ 💥 Erreur, la chaîne de type n'est pas attribuable à nombre
}
})
Mais nous pouvons toujours envoyer des codes de statut erronés (n'importe quel nombre est possible) et n'avons aucune idée des méthodes HTTP possibles (n'importe quelle chaîne est possible). Affinons nos types.
Ensembles plus petits
Vous pouvez voir les types primitifs comme un ensemble de toutes les valeurs possibles de cette certaine catégorie. Par exemple, string
inclut toutes les chaînes possibles qui peuvent être exprimées en JavaScript, number
inclut tous les nombres possibles avec une précision à double virgule. boolean
inclut toutes les valeurs booléennes possibles, qui sont true
et false
.
TypeScript vous permet d'affiner ces ensembles en sous-ensembles plus petits. Par exemple, nous pouvons créer un type Method
qui inclut toutes les chaînes possibles que nous pouvons recevoir pour les méthodes HTTP:
type Methods = "GET" | "POST" | "PUT" | "EFFACER";
type ServerRequest = {
méthode: méthodes;
paramètres: Record ;
};
La méthode
est un ensemble plus petit de l'ensemble de cordes plus grand
. La méthode
est un type d'union de types littéraux. Un type littéral est la plus petite unité d'un ensemble donné. Une chaîne littérale. Un nombre littéral. Il n'y a pas d'ambiguïté. C’est juste "GET"
. Vous les mettez dans une union avec d'autres types littéraux, créant un sous-ensemble de tous les types plus grands que vous avez. Vous pouvez également créer un sous-ensemble avec des types littéraux de chaîne
et numéro
ou différents types d'objets composés. Il y a beaucoup de possibilités pour combiner et mettre des types littéraux dans des unions.
Ceci a un effet immédiat sur notre rappel de serveur. Du coup, nous pouvons différencier ces quatre méthodes (ou plus si nécessaire), et épuiser toutes les possibilités du code. TypeScript nous guidera:
app.get ("/ api / users /: userID", function (req, res) {
// à ce stade, TypeScript sait que req.method
// peut prendre l'une des quatre valeurs possibles
commutateur (req.method) {
case "GET":
Pause;
cas "POST":
Pause;
case "DELETE":
Pause;
case "PUT":
Pause;
défaut:
// ici, req.method n'est jamais
req.method;
}
});
Avec chaque déclaration case
que vous faites, TypeScript peut vous donner des informations sur les options disponibles. Essayez-le par vous-même . Si vous avez épuisé toutes les options, TypeScript vous dira dans votre branche default
que cela ne peut jamais
se produire. Il s’agit littéralement du type jamais
ce qui signifie que vous avez peut-être atteint un état d’erreur que vous devez gérer.
C’est une catégorie d’erreurs en moins. Nous savons maintenant exactement quelles méthodes HTTP sont disponibles.
Nous pouvons faire de même pour les codes d'état HTTP, en définissant un sous-ensemble de nombres valides que statusCode
peut prendre:
type StatusCode =
100 | 101 | 102 | 200 | 201 | 202 | 203 | 204 | 205 |
206 | 207 | 208 | 226 | 300 | 301 | 302 | 303 | 304 |
305 | 306 | 307 | 308 | 400 | 401 | 402 | 403 | 404 |
405 | 406 | 407 | 408 | 409 | 410 | 411 | 412 | 413 |
414 | 415 | 416 | 417 | 418 | 420 | 422 | 423 | 424 |
425 | 426 | 428 | 429 | 431 | 444 | 449 | 450 | 451 |
499 | 500 | 501 | 502 | 503 | 504 | 505 | 506 | 507 |
508 | 509 | 510 | 511 | 598 | 599;
type ServerReply = {
envoyer: (obj ?: any) => void;
status: (statusCode: StatusCode) => ServerReply;
};
Type StatusCode
est à nouveau un type d'union. Et avec cela, nous excluons une autre catégorie d'erreurs. Soudain, un code comme celui-ci échoue:
app.get ("/ api / user /: userID", (req, res) => {
if (req.method === "POS") {
// ^^^^^^^^^^^^^^^^^^^^ 'Méthodes' et '"POS"' ne se chevauchent pas.
statut res. (20)
// ^^ '20' n'est pas assignable au paramètre de type 'StatusCode'
}
})
Et notre logiciel devient beaucoup plus sûr! Mais nous pouvons faire plus!
Enter Generics
Lorsque nous définissons une route avec app.get
nous savons implicitement que la seule méthode HTTP possible est "GET"
. Mais avec nos définitions de type, nous devons toujours vérifier toutes les parties possibles de l'union.
Le type de CallbackFn
est correct, car nous pourrions définir des fonctions de rappel pour toutes les méthodes HTTP possibles, mais si nous appeler explicitement app.get
ce serait bien de sauvegarder quelques étapes supplémentaires qui ne sont nécessaires que pour se conformer aux typages.
Les génériques TypeScript peuvent aider! Les génériques sont l'une des principales fonctionnalités de TypeScript qui vous permettent d'obtenir le comportement le plus dynamique des types statiques. Dans TypeScript in 50 Lessons nous passons les trois derniers chapitres à explorer toutes les subtilités des génériques et leurs fonctionnalités uniques.
Ce que vous devez savoir maintenant, c'est que nous voulons définir ServerRequest
de manière à pouvoir spécifier une partie de Methods
au lieu de l'ensemble complet. Pour cela, nous utilisons la syntaxe générique où nous pouvons définir des paramètres comme nous le ferions avec des fonctions:
type ServerRequest = {
méthode: Met;
paramètres: Record ;
};
Voici ce qui se passe:
-
ServerRequest
devient un type générique, comme indiqué par les crochets angulaires - Nous définissons un paramètre générique appelé
Met
qui est un sous-ensemble de typeMéthodes
- Nous utilisons ce paramètre générique comme variable générique pour définir la méthode.
Je vous encourage également à consulter mon article sur la dénomination des paramètres génériques . [19659006] Avec ce changement, nous pouvons spécifier différents ServerRequest
s sans dupliquer les choses:
type OnlyGET = ServerRequest;
type OnlyPOST = ServerRequest;
type POSTorPUT = ServerRquest;
Depuis que nous avons changé l'interface de ServerRequest
nous devons apporter des modifications à tous nos autres types qui utilisent ServerRequest
comme CallbackFn
et le get
function:
type CallbackFn = (
req: ServerRequest ,
réponse: ServerReply
) => vide;
function get (chemin: chaîne, rappel: CallbackFn <"GET">) {
// à implémenter
}
Avec la fonction get
nous passons un argument réel à notre type générique. Nous savons que ce ne sera pas simplement un sous-ensemble de Methods
nous savons exactement de quel sous-ensemble nous avons affaire.
Maintenant, lorsque nous utilisons app.get
nous ne faisons que ont une valeur possible pour req.method
:
app.get ("/ api / users /: userID", function (req, res) {
req.method; // peut seulement être obtenu
});
Cela garantit que nous ne supposons pas que des méthodes HTTP telles que "POST"
ou similaire sont disponibles lorsque nous créons un rappel app.get
. Nous savons exactement de quoi nous avons affaire à ce stade, alors reflétons cela dans nos types.
Nous avons déjà fait beaucoup pour nous assurer que request.method
est raisonnablement typé et représente l'état réel de affaires. Un avantage intéressant que nous obtenons avec le sous-ensemble du type d'union Methods
est que nous pouvons créer une fonction de rappel à usage général en dehors de de app.get
qui est de type sécurisé:
Gestionnaire de const: CallbackFn <"PUT" | "POST"> = function (res, req) {
res.method // peut être "POST" ou "PUT"
};
const handlerForAllMethods: CallbackFn = function (res, req) {
res.method // peut être toutes les méthodes
};
app.get ("/ api", gestionnaire);
// ^^^^^^^ 💥 Non, nous ne gérons pas "GET"
app.get ("/ api", handlerForAllMethods); // 👍 Cela fonctionne
Paramètres de frappe
Ce que nous n’avons pas encore touché, c’est de taper l’objet params
. Jusqu'à présent, nous obtenons un enregistrement qui permet d'accéder à chaque clé de chaîne
. C'est notre tâche maintenant de rendre cela un peu plus précis!
Nous faisons cela en ajoutant une autre variable générique. Une pour les méthodes, une pour les clés possibles dans notre Record
:
type ServerRequest = {
méthode: Met;
paramètres: Record ;
};
La variable de type générique Par
peut être un sous-ensemble de type string
et la valeur par défaut est chaque chaîne. Avec cela, nous pouvons dire à ServerRequest
quelles clés nous attendons:
// request.method = "GET"
// request.params = {
// ID utilisateur: chaîne
//}
type WithUserID = ServerRequest
Ajoutons le nouvel argument à notre fonction get
et au type CallbackFn
afin que nous puissions définir les paramètres demandés:
function get (
chemin: chaîne,
rappel: CallbackFn <"GET", Par>
) {
// à implémenter
}
type CallbackFn = (
req: ServerRequest ,
réponse: ServerReply
) => vide;
Si nous ne définissons pas explicitement Par
le type fonctionne comme nous en avons l'habitude, puisque Par
prend la valeur par défaut de string
. Si nous le définissons cependant, nous avons soudainement une définition correcte pour l'objet req.params
!
app.get <"userID"> ("/ api / users /: userID", function (req, res ) {
req.params.userID; // Travaux!!
req.params.anythingElse; // 💥 ne fonctionne pas !!
});
C’est génial! Il y a cependant une petite chose qui peut être améliorée. Nous pouvons toujours passer chaque chaîne à l'argument path
de app.get
. Ne serait-il pas mieux si nous pouvions y inclure également Par
?
Nous le pouvons! Avec la sortie de la version 4.1, TypeScript est capable de créer des types littéraux de modèle . Syntaxiquement, ils fonctionnent comme les littéraux de modèle de chaîne, mais au niveau du type. Là où nous avons pu diviser l'ensemble chaîne
en sous-ensembles avec des types littéraux de chaîne (comme nous l'avons fait avec les méthodes), les types littéraux modèles nous permettent d'inclure tout un spectre de chaînes. [19659006] Créons un type appelé IncludesRouteParams
où nous voulons nous assurer que Par
est correctement inclus dans la manière de style Express d'ajouter un deux-points devant le nom du paramètre: [19659007] type includesRouteParams
| `$ {chaîne} /: $ {Par}`
| `$ {chaîne} /: $ {Par} / $ {chaîne}`;
Le type générique IncludesRouteParams
prend un argument, qui est un sous-ensemble de la chaîne
. Il crée un type d'union de deux littéraux de gabarit:
- Le premier littéral de gabarit commence par n'importe quelle chaîne
/
suivi d'un:
suivi du nom du paramètre. Cela garantit que nous interceptons tous les cas où le paramètre est à la fin de la chaîne de route. - Le deuxième littéral de modèle commence par any
string
suivi du même modèle de/
:
et le nom du paramètre. Ensuite, nous avons un autre caractère/
suivi de n'importe quelle chaîne . Cette branche du type union garantit que nous interceptons tous les cas où le paramètre est quelque part dans une route.
Voici comment IncludesRouteParams
avec le nom de paramètre userID
se comporte avec différents cas de test :
const a: IncludeRouteParams = "/ api / user /: userID" // 👍
const a: IncludeRouteParams = "/ api / user /: userID / orders" // 👍
const a: IncludeRouteParams = "/ api / user /: userId" // 💥
const a: IncludeRouteParams = "/ api / user" // 💥
const a: IncludeRouteParams = "/ api / user /: userIDAndmore" // 💥
Incluons notre nouveau type d’utilitaire dans la déclaration de la fonction get
.
function get (
chemin: includesRouteParams ,
rappel: CallbackFn <"GET", Par>
) {
// à implémenter
}
app.get <"userID"> (
"/ api / users /: userID",
function (req, res) {
req.params.userID; // OUAIS!
}
);
Génial! Nous obtenons un autre mécanisme de sécurité pour nous assurer de ne pas manquer d'ajouter les paramètres à l'itinéraire réel! Quelle puissance.
Fixations génériques
Mais devinez quoi, je ne suis toujours pas satisfait. Il y a quelques problèmes avec cette approche qui deviennent apparents au moment où vos routes deviennent un peu plus complexes.
- Le premier problème que j'ai est que nous devons déclarer explicitement nos paramètres dans le paramètre de type générique. Nous devons lier
Par
à"userID"
même si nous le spécifierions quand même dans l'argument path de la fonction. Ce n'est pas JavaScript-y! - Cette approche ne gère qu'un seul paramètre d'itinéraire. Au moment où nous ajoutons une union, par exemple
"userID" | "orderId"
la vérification de sécurité est satisfaite avec seulement un de ces arguments étant disponible. Voilà comment fonctionnent les décors. Cela peut être l'un ou l'autre.
Il doit y avoir un meilleur moyen. Et voici. Sinon, cet article se terminerait sur une note très amère.
Inversons l’ordre! N'essayons pas de définir les paramètres de route dans une variable de type générique, mais extrayons plutôt les variables du chemin
que nous passons comme premier argument de app.get
.
Pour obtenir à la valeur réelle, nous devons voir comment liaison générique fonctionne dans TypeScript. Prenons par exemple cette fonction identity
:
function identity (inp: T): T {
retour inp
}
C'est peut-être la fonction générique la plus ennuyeuse que vous ayez jamais vue, mais elle illustre parfaitement un point. identity
prend un argument et renvoie à nouveau la même entrée. Le type est le type générique T
et il renvoie également le même type.
Nous pouvons maintenant lier T
à string
par exemple: [19659007] const z = identité
Cette liaison explicitement générique garantit que nous ne transmettons que les chaînes
à identity
et puisque nous lions explicitement, le type de retour est également string
. Si nous oublions de lier, quelque chose d'intéressant se produit:
const y = identity ("yes") // y est de type "yes"
Dans ce cas, TypeScript déduit le type de l'argument que vous passez et lie T
au type littéral de chaîne "yes"
. C'est un excellent moyen de convertir un argument de fonction en un type littéral, que nous utilisons ensuite dans nos autres types génériques.
Faisons cela en adaptant app.get
.
function get ] (
chemin: chemin,
rappel: CallbackFn <"GET", ParseRouteParams >
) {
// à implémenter
}
Nous supprimons le type générique Par
et ajoutons Path
. Path
peut être un sous-ensemble de n'importe quelle chaîne
. Nous définissons path
sur ce type générique Path
ce qui signifie qu'au moment où nous passons un paramètre à get
nous capturons son type littéral de chaîne. Nous passons Path
à un nouveau type générique ParseRouteParams
que nous n’avons pas encore créé.
Travaillons sur ParseRouteParams
. Ici, nous inversons à nouveau l'ordre des événements. Au lieu de passer les paramètres de route demandés au générique pour nous assurer que le chemin est correct, nous passons le chemin de route et extrayons les paramètres de route possibles. Pour cela, nous devons créer un type conditionnel.
Types conditionnels et types littéraux de modèle récursif
Les types conditionnels sont syntaxiquement similaires à l'opérateur ternaire en JavaScript. Vous vérifiez une condition, et si la condition est remplie, vous retournez la branche A, sinon, vous retournez la branche B. Par exemple:
type ParseRouteParams =
Rte étend `$ {string} /: $ {infer P}`
? P
: jamais;
Ici, nous vérifions si Rte
est un sous-ensemble de chaque chemin qui se termine par le paramètre à la fin de style Express (avec un "/:"
). Si tel est le cas, nous déduisons cette chaîne. Ce qui signifie que nous capturons son contenu dans une nouvelle variable. Si la condition est remplie, nous retournons la chaîne nouvellement extraite, sinon, nous retournons jamais, comme dans: "Il n'y a pas de paramètres d'itinéraire",
Si nous l'essayons, nous obtenons quelque chose comme ça:
type Params = ParseRouteParams <"/api/user/:userID"> // Le paramètre est "userID"
type NoParams = ParseRouteParams <"/api/user"> // NoParams n'est jamais -> pas de paramètres!
Génial, c'est déjà bien mieux que ce que nous faisions auparavant. Maintenant, nous voulons attraper tous les autres paramètres possibles. Pour cela, nous devons ajouter une autre condition:
type ParseRouteParams = Rte étend `$ {string} /: $ {infer P} / $ {infer Rest}`
? P | ParseRouteParams <`/${Rest}`>
: Rte étend `$ {string} /: $ {infer P}`
? P
: jamais;
Notre type conditionnel fonctionne maintenant comme suit:
- Dans la première condition, nous vérifions s'il y a un paramètre d'itinéraire quelque part entre l'itinéraire. Si tel est le cas, nous extrayons à la fois le paramètre de route et tout ce qui suit. Nous retournons le paramètre d'itinéraire nouvellement trouvé
P
dans une union où nous appelons le même type générique récursivement avec leRest
. Par exemple, si nous transmettons la route"/ api / users /: userID / orders /: orderID"
àParseRouteParams
nous déduisons"userID"
dansP
et"orders /: orderID"
inRest
. On appelle le même type avecRest
- C'est là qu'intervient la deuxième condition. Ici on vérifie s'il y a un type à la fin. C'est le cas pour
"orders /: orderID"
. Nous extrayons"orderID"
et retournons ce type littéral. - S'il n'y a plus de paramètre d'itinéraire, nous ne retournons jamais.
Dan Vanderkam montre un semblable, et plus type élaboré pour ParseRouteParams
mais celui que vous voyez ci-dessus devrait également fonctionner. Si nous essayons notre nouvellement adapté ParseRouteParams
nous obtenons quelque chose comme ceci:
// Params est "userID"
type Params = ParseRouteParams
Appliquons ce nouveau type et voyons à quoi ressemble notre utilisation finale de app.get
.
app.get ("/ api / users /: userID / orders /: orderID ", function (req, res) {
req.params.userID; // OUI!!
req.params.orderID; // Aussi OUI !!!
});
Wow. Cela ressemble au code JavaScript que nous avions au début!
Types statiques pour un comportement dynamique
Les types que nous venons de créer pour une fonction app.get
garantissent que nous excluons une tonne de possibles erreurs:
- Nous ne pouvons transmettre les codes d'état numériques appropriés qu'à
res.status ()
-
req.method
est l'une des quatre chaînes possibles, et lorsque nous utilisonsapp.get
nous savons que ce n'est que"GET"
- Nous pouvons analyser les paramètres d'itinéraire et nous assurer que nous n'avons pas de fautes de frappe dans notre rappel
Si nous regardons à l'exemple du début de cet article, nous obtenons les messages d'erreur suivants:
app.get ("/ api / users /: userID", function (req, res) {
if (req.method === "POST") {
// ^^^^^^^^^^^^^^^^^^^^^
// Cette condition retournera toujours 'false'
// puisque les types '"GET"' et '"POST"' ne se chevauchent pas.
res.status (20) .send ({
// ^^
// L'argument de type '20' n'est pas assignable à
// paramètre de type 'StatusCode'
message: "Bienvenue, utilisateur" + req.params.userId
// ^^^^^^
// La propriété 'userId' n'existe pas sur le type
// '{ID utilisateur: chaîne; } '. Vouliez-vous dire 'userID'?
});
}
})
Et tout cela avant de lancer notre code! Les serveurs de style express sont un parfait exemple de la nature dynamique de JavaScript. Selon la méthode que vous appelez, la chaîne que vous passez pour le premier argument, de nombreux changements de comportement dans le rappel. Prenons un autre exemple et tous vos types sont complètement différents.
Mais avec quelques types bien définis, nous pouvons détecter ce comportement dynamique lors de l'édition de notre code. Au moment de la compilation avec les types statiques, pas au moment de l'exécution quand les choses tournent en plein essor!
Et c'est la puissance de TypeScript. Un système de type statique qui tente de formaliser tout le comportement JavaScript dynamique que nous connaissons tous si bien. Si vous voulez essayer l'exemple que nous venons de créer, rendez-vous sur le terrain de jeu TypeScript et manipulez-le.
Dans cet article, nous avons abordé de nombreuses concepts. Si vous souhaitez en savoir plus, consultez TypeScript in 50 Lessons où vous découvrirez en douceur le système de type dans de petites leçons faciles à digérer. Les versions d'ebook sont disponibles immédiatement et le livre imprimé constituera une excellente référence pour votre bibliothèque de codage.

Source link