Person
& Serializable
& Loggable
est une personne
et Serializable
et Loggable
.
Cela signifie qu'un objet de ce type aura tous les membres des trois types.mixin
et d'autres concepts qui ne rentrent pas dans le moule classique orienté objet.
( Il y en a beaucoup en JavaScript
! ).mixin
:number
ou un string
.padLeft
est que son paramètre padding
est tapé comme any
.
Cela signifie que nous pouvons l'appeler avec un argument qui n'est ni un number
ni un string
, mais TypeScript
l'acceptera.padLeft
est que nous n'avons pu passer que des primitives.
Cela signifiait que l'utilisation était simple et concise.
Cette nouvelle approche ne nous aiderait pas non plus si nous essayions simplement d'utiliser une fonction qui existe déjà ailleurs.any
, nous pouvons utiliser un type d'union pour le paramètre padding
:|
) pour séparer chaque type, de même que number | string | boolean
le type d'une valeur qui peut être a number
,
a string
ou a boolean
.A | B
, nous savons seulement avec certitude qu'elle a des membres qui ont tous les deux A
et
B.
Dans cet exemple, Bird
est membre est nommé fly
.
Nous ne pouvons pas être sûrs qu'une variable typée Bird | Fish
a une méthode fly
.
Si la variable est vraiment un Fish
à l'exécution, l'appel pet.fly()
échouera.Fish
?
Un langage courant JavaScript
pour différencier deux valeurs possibles la solution est de vérifier la présence d'un membre.
Comme nous l'avons mentionné, vous ne pouvez accéder qu'aux membres dont il est garanti qu'ils appartiennent à tous les groupes constitutifs d'un type syndical.pet
.TypeScript
a quelque chose appelé un type guard
.
Un type guard
est une expression qui effectue une vérification à l'exécution qui garantit le type dans une certaine portée.
Pour définir une protection de type, nous devons simplement définir une fonction dont le type de retour est un prédicat de type :pet is Fish
est notre prédicat de type dans cet exemple.
Un prédicat prend la forme parameterName is Type
, où parameterName
doit être le nom d'un paramètre de la signature de la fonction actuelle.isFish
appelé avec une variable, TypeScript
restreindra cette variable à ce type spécifique si le type d'origine est compatible.TypeScript
non seulement sait que pet
est un Fish
dans la branche; il sait aussi que dans la branche else
,
vous n'avez un Fish
, vous devez donc un Bird
padLeft
qui utilise des types d'union.
Nous pourrions l'écrire avec les prédicats de type comme suit :typeof x === "number"
dans sa propre fonction car TypeScript
le reconnaîtra comme un garde de type.
Cela signifie que nous pourrions simplement écrire ces chèques en ligne.typeof
sont reconnus sous deux formes différentes :
typeof v === "typename"
et typeof v !== "typename"
où "typename"
doit être "number"
, "string"
, "boolean"
ou "symbol"
.
Bien que TypeScript
ne vous empêche pas de comparer d'autres chaînes, le langage ne reconnaît pas ces expressions en tant que gardes du type.typeof
les polices de caractères et connaissez instanceof
de l'opérateur JavaScript
,
vous avez probablement une idée de ce à quoi sert cette section.instanceof
permettent de réduire les types à l'aide de leur fonction constructeur.
Prenons, par exemple, notre exemple de dépisteur de cordes industriel :instanceof
doit être une fonction constructeur, et TypeScript
se limitera à :prototype
de la fonction si son type n'est pas any
TypeScript
a deux types spéciaux, null
et undefined
, qui ont respectivement les valeurs null
et indéfinie.
Nous en avons parlé brièvement dans la section Types de base.
Par défaut, le vérificateur de type considère null
et peut être undefined
assigné à quoi que ce soit.
Effectivement, null
et undefined
sont des valeurs valides de chaque type.
Cela signifie qu'il n'est pas possible d'empêcher leur assignation à quelque type que ce soit, même si vous souhaitez l'empêcher.
L'inventeur de null
Tony Hoare appelle cela "son erreur d'un milliard de dollars".--strictNullChecks
corrige ceci : lorsque vous déclarez une variable, elle n'inclut pas automatiquement null
ni undefined
.
Vous pouvez les inclure explicitement en utilisant un type d'union :TypeScript
traite null
et undefined
différemment afin de correspondre à la sémantique JavaScript
.
string | null
est un type différent de string | undefined
et string | undefined | null
.--strictNullChecks
, un paramètre optionnel ajoute automatiquement | undefined
:guard
pour vous en débarrasser null
.
Heureusement, c'est le même code que vous écriviez en JavaScript :null
est assez évidente ici, mais vous pouvez aussi utiliser des opérateurs de terser :null
ou undefined
, vous pouvez utiliser l'opérateur d'assertion de type pour les supprimer manuellement.
La syntaxe est postfix !
: identifier!
supprime null
et undefined
du type de identifier :interfaced
dans un éditeur montrera qu'il retourne un Interface
,
mais montrera que aliased
retourne le type littéral d'objet.TypeScript
a aussi des types littéraux numériques.x
doit être 1
quand il est comparé à 2
,
ce qui signifie que la vérification ci-dessus fait une comparaison invalide.enum
et aux types littéraux numériques / chaînes,
même si de nombreux utilisateurs utiliseront indifféremment les "types singleton" et les "types littéraux".TypeScript
s'appuie sur les modèles JavaScript
tels qu'ils existent aujourd'hui. Triangle
à Shape
, nous devons également mettre à jour area
:--strictNullChecks
et à spécifier un type de retour :switch
n'est plus exhaustif, TypeScript
est conscient que la fonction peut parfois être retournée undefined
.
Si vous avez un type de retour explicite number
, vous obtiendrez une erreur indiquant que le type de retour est réellement number | undefined
.
Cependant, cette méthode est assez subtile et --strictNullChecks
ne fonctionne pas toujours avec l'ancien code.never
, utilisé par le compilateur pour vérifier l'exhaustivité :assertNever
contrôles s
de type never
, le type qui reste après la suppression de tous les autres cas.
Si vous oubliez un cas, vous saurez un type réel et vous obtiendrez une erreur de type.
Cette méthode nécessite de définir une fonction supplémentaire, mais c'est beaucoup plus évident quand vous l'oubliez.this
polymorphe représente un type qui est le sous type de la classe ou de l'interface qui le contient.
Ceci est appelé polymorphisme lié à F. Cela rend les interfaces fluides hirarchiques beaucoup plus faciles à exprimer, par exemple.
Prenons une simple calculatrice qui retourne this après chaque opération :
this
, ScientificCalculator
n'aurait pas été en mesure d'étendre BasicCalculator
et de maintenir l'interface fluide.
multiply serait retourné BasicCalculator
, qui n'a pas la méthode sin
.
Cependant, avec les types this
, les retours multiply
this
, ce qui est ScientificCalculator
ici.
Javascript
courant consiste à choisir un sous-ensemble de propriétés dans un objet :TypeScript
, à l'aide de la requête de type d'index et des opérateurs d'accès indexés :name
s'agit bien d'une propriété Person
.
L'exemple introduit quelques nouveaux opérateurs de type.
Le premier est keyof T
l'opérateur de requête de type index.
Pour tout type T
, keyof T
est l'union des noms de propriété publique connus de T
.keyof Person
est complètement interchangeable avec 'name' | 'age'
.
La différence est que si vous ajoutez une autre propriété à Person
, par exemple address : string
,
elle keyof Person
sera automatiquement mise à jour 'name' | 'age' | 'address'
.
Et vous pouvez utiliser keyof
des contextes génériques tels que pluck
,
où vous ne pouvez pas connaître les noms de propriété à l'avance.
Cela signifie que le compilateur vérifiera que vous transmettez le bon ensemble de noms de propriétés à pluck
:T[K]
l'opérateur d'accès indexé.
Ici, la syntaxe de type reflète la syntaxe d'expression.
Cela signifie que cela person['name']
a le type Person['name']
ce qui dans notre exemple est juste string
.
Cependant, tout comme les requêtes de type index, vous pouvez utiliser T[K]
un contexte générique, où son pouvoir réel prend vie.
Vous devez juste vous assurer que le type variable K extends keyof T
. Voici un autre exemple avec une fonction nommée getProperty
.getProperty, o: T
et name: K
, donc ça veut dire o[name]: T[K]
.
Une fois que vous avez renvoyé le résultat T[K]
, le compilateur instancie le type actuel de la clé.
Le type de retour getProperty
varie en fonction de la propriété que vous demandez.keyof
et T[K]
interagir avec les signatures d'index de chaîne.
Si vous avez un type avec une signature d'index de chaîne, ce keyof
T
sera juste string
.
Et T[string]
est juste le type de la signature d'index :Javascript
que TypeScript
offre un moyen de créer de nouveaux types basés sur d'anciens types - types mappés.
Dans un type mappé, le nouveau type transforme chaque propriété de l'ancien type de la même manière.
Par exemple, vous pouvez rendre toutes les propriétés d'un type readonly
ou facultatives.for .. in
intérieur. Il y a trois parties :K
, qui est liée à chaque propriété.Keys
, qui contient les noms des propriétés à itérer.Keys
est une liste codée en dur de noms de propriétés et le type de propriété est toujours boolean
,
de sorte que ce type mappé est équivalent à l'écriture :Readonly
ou Partial
dépassent.
Ils sont basés sur un type existant et transforment les propriétés d'une manière ou d'une autre.
C'est là que keyof
interviennent les types d'accès indexés :keyof T
et le type résultant est une variante de T[P]
.
C'est un bon modèle pour toute utilisation générale des types mappés.
En effet, ce type de transformation est homomorphique, ce qui signifie que le mappage s'applique uniquement aux propriétés des T
autres propriétés.
Le compilateur sait qu'il peut copier tous les modificateurs de propriétés existants avant d'en ajouter de nouveaux.
Par exemple, si Person.name
était en lecture seule, Partial‹Person›.name
serait en lecture seule et facultatif.T[P]
est encapsulé dans une classe Proxy‹T›
:Readonly‹T›
et Partial‹T›
sont très utiles, ils sont inclus dans la bibliothèque standard de TypeScript
avec Picket Record
:Readonly
, Partial
et Pick
sont homomorphic alors que Record
ne l'est pas.
Un indice qui Record
n'est pas homomorphe est qu'il ne faut pas un type d'entrée pour copier les propriétés de :TypeScript 2.8
introduit des types conditionnels qui permettent d'exprimer des mappages de types non uniformes.
Un type conditionnel sélectionne l'un des deux types possibles en fonction d'une condition exprimée sous la forme d'un test de relation de type :T
est assignable au U
type est X
, sinon le type est Y
.T
extends U ? X
: Y
est résolu en X
ou Y
,
ou différé car la condition dépend d'une ou de plusieurs variables de type.
Lorsque T
ou U
contient des variables de type, la résolution en X
ou Y
,
ou en différé, est déterminée par le fait que le système de types possède suffisamment d'informations pour conclure qu'il T
est toujours assignable U
.TypeName
de type, qui utilise des types conditionnels imbriqués :a
a un type conditionnel qui n'a pas encore choisi de branche.
Quand un autre morceau de code finit par appeler foo
, il sera remplacé U
par un autre type et TypeScript
réévaluera le type conditionnel,
en décidant s'il peut réellement choisir une branche.U extends Foo ? string : number
à, string | number
peu importe ce que le
conditionnel évalue, il est connu pour être l'un string
ou l'autre number
.T extends U ? X : Y
avec l'argument type A | B | C
pour T
est résolue
en tant que (A extends U ? X : Y) | (B extends U ? X : Y) | (C extends U ? X : Y)
.T extends U ? X : Y
, les références au T
type conditionnel sont
résolues en constituants individuels du type union (c'est-à- dire, T
fait référence aux constituants individuels une fois que
le type conditionnel est distribué sur le type union). De plus, les références à T
inside X
ont une contrainte de paramètre de
type supplémentaire U
(c'est-à-dire T
qu'elles sont assignables à U
dedans X
).T
a la contrainte supplémentaire any[]
dans la branche vraie de Boxed‹T› et il est donc possible de se référer au type
d'élément du tableau comme T[number]
. Notez également comment le type conditionnel est distribué sur le type d'union dans le dernier exemple.extends
d'un type conditionnel, il est maintenant possible d'avoir des déclarations qui introduisent une variable de type à inférer.
De telles variables de type inféré peuvent être référencées dans la branche vraie du type conditionnel. Il est possible d'avoir plusieurs
inferemplacements pour la même variable de type.TypeScript 2.8
ajoute plusieurs types conditionnels prédéfinis à lib.d.ts
:Exclude‹T, U›
- Exclure de T
ces types qui sont assignables à U
.Extract‹T, U›
- Extrait de T
ces types qui sont assignables à U
.NonNullable‹T›
- Exclure null
et undefined de T
.ReturnType‹T›
- Obtenir le type de retour d'un type de fonction.InstanceType‹T›
- Obtenir le type d'instance d'un type de fonction constructeur.Exclude
correspond à une implémentation appropriée du type Diff
suggéré ici.
Nous avons utilisé le nom Exclude
pour éviter de casser le code existant qui définit un Diff
,
et nous pensons que ce nom véhicule mieux la sémantique du type. Nous n'avons pas inclus le Omit‹T, K›
type car il
est écrit trivialement comme Pick‹T, Exclude‹keyof T, K››
.