TypeScript est un langage typé qui vous permet de spécifier le type de variables, les paramètres de fonction, les valeurs renvoyées et les propriétés d'objet.
Voici un aide-mémoire sur les Types TypeScript avancés avec des exemples.
Sorry for the interrupt!
If you're interested in learning TypeScript in a comprehensive way, I highly recommend this bestseller course: Understanding TypeScript - 2020 Edition
It's an affiliate link, so by purchasing, you support the blog at the same time.- Les Types d'intersection
- Les Types d'unions
- Les Types génériques
- Les Types mappés
- Les Gardes de type
- Les Types conditionnels
Les Types d'intersection
Un type d'intersection est un moyen de combiner plusieurs types en un seul. Cela signifie que vous pouvez fusionner un type donné A avec un type B ou plus et récupérer en retour un seul type avec toutes les propriétés fusionnées.
type LeftType = {
id: number
left: string
}
type RightType = {
id: number
right: string
}
type IntersectionType = LeftType & RightType
function showType(args: IntersectionType) {
console.log(args)
}
showType({ id: 1, left: "test", right: "test" })
// Output: {id: 1, left: "test", right: "test"}
Comme vous pouvez le voir, IntersectionType
combine deux types: LeftType
et RightType
et utilise le signe &
pour construire le type d'intersection.
Les Types d'unions
Les types d'union vous permettent d'avoir des annotations de types différents dans une variable donnée.
type UnionType = string | number
function showType(arg: UnionType) {
console.log(arg)
}
showType("test")
// Output: test
showType(7)
// Output: 7
La fonction showType
est un type d'union qui accepte à la fois des chaînes et des nombres comme paramètre.
Les Types génériques
Un type générique est un moyen de réutiliser une partie d'un type donné. Il aide à capturer le type T
transmis comme argument.
function showType<T>(args: T) {
console.log(args)
}
showType("test")
// Output: "test"
showType(1)
// Output: 1
Pour construire un type générique, vous devez utiliser les crochets et passer T
en paramètre.
Ici, j'utilise T
(le nom dépend de vous), puis j'appelle deux fois la fonction showType
avec des annotations de types différents car elle est générique, elle peut être réutilisée.
interface GenericType<T> {
id: number
name: T
}
function showType(args: GenericType<string>) {
console.log(args)
}
showType({ id: 1, name: "test" })
// Output: {id: 1, name: "test"}
function showTypeTwo(args: GenericType<number>) {
console.log(args)
}
showTypeTwo({ id: 1, name: 4 })
// Output: {id: 1, name: 4}
Ici, nous avons un autre exemple qui a une interface GenericType
qui reçoit un type générique T
. Et comme il est réutilisable, nous pouvons l'appeler avec d'abord une chaîne, puis un numéro.
interface GenericType<T, U> {
id: T
name: U
}
function showType(args: GenericType<number, string>) {
console.log(args)
}
showType({ id: 1, name: "test" })
// Output: {id: 1, name: "test"}
function showTypeTwo(args: GenericType<string, string[]>) {
console.log(args)
}
showTypeTwo({ id: "001", name: ["This", "is", "a", "Test"] })
// Output: {id: "001", name: Array["This", "is", "a", "Test"]}
Un type générique peut recevoir plusieurs arguments. Ici, nous passons deux paramètres: T
et U
, puis nous les utilisons comme annotations de type pour les propriétés. Cela dit, nous pouvons maintenant utiliser l'interface et fournir différents types comme argument.
Les Types d'utilitaires
TypeScript fournit des utilitaires intégrés pratiques qui aident à manipuler facilement les types. Pour les utiliser, vous devez passer dans le <>
le type que vous souhaitez transformer.
Partial
Partial<T>
Partial vous permet de rendre toutes les propriétés du type T
facultatives. Il ajoutera une marque ?
à côté de chaque champ.
interface PartialType {
id: number
firstName: string
lastName: string
}
function showType(args: Partial<PartialType>) {
console.log(args)
}
showType({ id: 1 })
// Output: {id: 1}
showType({ firstName: "John", lastName: "Doe" })
// Output: {firstName: "John", lastName: "Doe"}
Comme vous pouvez le voir, nous avons une interface PartialType
qui est utilisée comme annotation de type pour les paramètres reçus par la fonction showType()
. Et pour rendre les propriétés facultatives, nous devons utiliser le mot clé Partial
et passer le type PartialType
comme argument. Cela dit, tous les champs deviennent maintenant facultatifs.
Required
Required<T>
Contrairement à Partial
, l'utilitaire Required
rend toutes les propriétés du type T
obligatoires.
interface RequiredType {
id: number
firstName?: string
lastName?: string
}
function showType(args: Required<RequiredType>) {
console.log(args)
}
showType({ id: 1, firstName: "John", lastName: "Doe" })
// Output: { id: 1, firstName: "John", lastName: "Doe" }
showType({ id: 1 })
// Error: Type '{ id: number: }' is missing the following properties from type 'Required<RequiredType>': firstName, lastName
L'utilitaire Required
rendra toutes les propriétés requises même si nous les rendons facultatives avant d'utiliser l'utilitaire. Et si une propriété est omise, TypeScript enverra une erreur.
Readonly
Readonly<T>
Ce type d'utilitaire transformera toutes les propriétés du type T
afin de les rendre non réaffectables avec une nouvelle valeur.
interface ReadonlyType {
id: number
name: string
}
function showType(args: Readonly<ReadonlyType>) {
args.id = 4
console.log(args)
}
showType({ id: 1, name: "Doe" })
// Error: Cannot assign to 'id' because it is a read-only property.
Ici, nous utilisons l'utilitaire Readonly
pour rendre les propriétés de ReadonlyType
non réaffectables. Cela dit, si vous essayez de donner une nouvelle valeur à l'un de ces champs, une erreur sera générée.
En plus de cela, vous pouvez également utiliser le mot clé readonly
devant une propriété pour la rendre non réaffectable.
interface ReadonlyType {
readonly id: number
name: string
}
Pick
Pick<T, K>
Il vous permet de créer un nouveau type à partir d'un modèle existant T
en sélectionnant certaines propriétés K
de ce type.
interface PickType {
id: number
firstName: string
lastName: string
}
function showType(args: Pick<PickType, "firstName" | "lastName">) {
console.log(args)
}
showType({ firstName: "John", lastName: "Doe" })
// Output: {firstName: "John"}
showType({ id: 3 })
// Error: Object literal may only specify known properties, and 'id' does not exist in type 'Pick<PickType, "firstName" | "lastName">'
Pick
est un peu différent des utilitaires précédents que nous avons déjà vus. Il attend deux paramètres: T
est le type à partir duquel vous souhaitez sélectionner des éléments et K
qui est la propriété que vous souhaitez sélectionner. Vous pouvez également sélectionner plusieurs champs en les séparant par un symbole de tuyau (|
).
Omit
Omit<T, K>
L'utilitaire Omit
est l'opposé du type Pick
. Et au lieu de sélectionner des éléments, il supprimera les propriétés K
du type T
.
interface PickType {
id: number
firstName: string
lastName: string
}
function showType(args: Omit<PickType, "firstName" | "lastName">) {
console.log(args)
}
showType({ id: 7 })
// Output: {id: 7}
showType({ firstName: "John" })
// Error: Object literal may only specify known properties, and 'firstName' does not exist in type 'Pick<PickType, "id">'
Cet utilitaire est similaire à la façon dont Pick
fonctionne. Il attend le type et les propriétés à omettre de ce type.
Extract
Extract<T, U>
Extract
vous permet de construire un type en choisissant des propriétés présentes dans deux types différents. L'utilitaire extraira de T
toutes les propriétés attribuables à U
.
interface FirstType {
id: number
firstName: string
lastName: string
}
interface SecondType {
id: number
address: string
city: string
}
type ExtractType = Extract<keyof FirstType, keyof SecondType>
// Output: "id"
Ici, nous avons deux types qui ont en commun la propriété id
. Et donc en utilisant le mot-clé Extract
, nous récupérons le champ id
car il est présent dans les deux interfaces. Et si vous avez plusieurs champs partagés, l'utilitaire extraira toutes les propriétés similaires.
Exclude
Contrairement à Extract
, l'utilitaire Exclude
construira un type en excluant les propriétés qui sont déjà présentes dans deux types différents. Il exclut de T
tous les champs attribuables à U
.
interface FirstType {
id: number
firstName: string
lastName: string
}
interface SecondType {
id: number
address: string
city: string
}
type ExcludeType = Exclude<keyof FirstType, keyof SecondType>
// Output; "firstName" | "lastName"
Comme vous pouvez le voir ici, les propriétés firstName
et lastName
sont assignables au type SecondType
car elles n'y sont pas présentes. Et en utilisant le mot-clé Extract
, nous récupérons ces champs comme prévu.
Record
Record<K, T>
Cet utilitaire vous aide à construire un type avec un ensemble de propriétés K
d'un type donné T
. Record
est vraiment pratique quand il s'agit de mapper les propriétés d'un type à un autre.
interface EmployeeType {
id: number
fullname: string
role: string
}
let employees: Record<number, EmployeeType> = {
0: { id: 1, fullname: "John Doe", role: "Designer" },
1: { id: 2, fullname: "Ibrahima Fall", role: "Developer" },
2: { id: 3, fullname: "Sara Duckson", role: "Developer" },
}
// 0: { id: 1, fullname: "John Doe", role: "Designer" },
// 1: { id: 2, fullname: "Ibrahima Fall", role: "Developer" },
// 2: { id: 3, fullname: "Sara Duckson", role: "Developer" }
Le fonctionnement de Record
est relativement simple. Ici, il attend un nombre comme type, c'est pourquoi nous avons 0, 1 et 2 comme clés pour la variable employees
. Et si vous essayez d'utiliser une chaîne comme propriété, une erreur sera génerée. Ensuite, l'ensemble des propriétés est donné par EmployeeType
d'où l'objet avec les champs id, fullName et role.
NonNullable
NonNullable<T>
Il vous permet de supprimer null
et undefined
du type T
.
type NonNullableType = string | number | null | undefined
function showType(args: NonNullable<NonNullableType>) {
console.log(args)
}
showType("test")
// Output: "test"
showType(1)
// Output: 1
showType(null)
// Error: Argument of type 'null' is not assignable to parameter of type 'string | number'.
showType(undefined)
// Error: Argument of type 'undefined' is not assignable to parameter of type 'string | number'.
Ici, nous passons le type NonNullableType
comme argument à l'utilitaire NonNullable
qui construit un nouveau type en excluant null
et undefined
de ce type. Cela dit, si vous passez une valeur nulle, TypeScript enverra une erreur.
Par ailleurs, si vous ajoutez l'indicateur --strictNullChecks
au fichier tsconfig
, TypeScript appliquera des règles de non-nullabilité.
Les Types mappés
Les types mappés vous permettent de prendre un modèle existant et de transformer chacune de ses propriétés en un nouveau type. Notez que certains types d'utilitaires couverts précédemment sont également des types mappés.
type StringMap<T> = {
[P in keyof T]: string
}
function showType(arg: StringMap<{ id: number; name: string }>) {
console.log(arg)
}
showType({ id: 1, name: "Test" })
// Error: Type 'number' is not assignable to type 'string'.
showType({ id: "testId", name: "This is a Test" })
// Output: {id: "testId", name: "This is a Test"}
StringMap<>
transformera tous les types transmis en chaîne. Cela dit, si nous l'utilisons dans la fonction showType()
, les paramètres reçus doivent être une chaîne, sinon, une erreur sera générée par TypeScript.
Les Gardes de type
Les gardes de type vous permettent de vérifier le type d'une variable ou d'un objet avec un opérateur. Il s'agit d'un bloc conditionnel qui renvoie un type en utilisant typeof
, instanceof
ou in
.
typeof
function showType(x: number | string) {
if (typeof x === "number") {
return `The result is ${x + x}`
}
throw new Error(`This operation can't be done on a ${typeof x}`)
}
showType("I'm not a number")
// Error: This operation can't be done on a string
showType(7)
// Output: The result is 14
Comme vous pouvez le voir, nous avons un bloc conditionnel JavaScript normal qui vérifie le type de l'argument reçu avec typeof
. Avec cela en place, vous pouvez maintenant protéger votre type avec cette condition.
instanceof
class Foo {
bar() {
return "Hello World"
}
}
class Bar {
baz = "123"
}
function showType(arg: Foo | Bar) {
if (arg instanceof Foo) {
console.log(arg.bar())
return arg.bar()
}
throw new Error("The type is not supported")
}
showType(new Foo())
// Output: Hello World
showType(new Bar())
// Error: The type is not supported
Comme l'exemple précédent, celui-ci est également un garde de type qui vérifie si le paramètre reçu fait partie de la classe Foo
ou non et le gère en conséquence.
in
interface FirstType {
x: number
}
interface SecondType {
y: string
}
function showType(arg: FirstType | SecondType) {
if ("x" in arg) {
console.log(`The property ${arg.x} exists`)
return `The property ${arg.x} exists`
}
throw new Error("This type is not expected")
}
showType({ x: 7 })
// Output: The property 7 exists
showType({ y: "ccc" })
// Error: This type is not expected
L'opérateur in
vous permet de vérifier si la propriété x
existe ou non sur l'objet reçu en paramètre.
Les Types conditionnels
Il teste deux types et en sélectionne un en fonction du résultat de ce test.
type NonNullable<T> = T extends null | undefined ? never : T
Cet exemple de type d'utilitaire NonNullable
vérifie si le type est nul ou non et le gère en fonction de cela. Et comme vous pouvez le constater, il utilise l'opérateur ternaire JavaScript.
Merci d'avoir lu.