Dans TypeScript 3.8+, quelles sont les différences entre l'utilisation du private
mot - clé pour marquer un membre comme privé:
class PrivateKeywordClass {
private value = 1;
}
Et en utilisant les #
champs privés proposés pour JavaScript :
class PrivateFieldClass {
#value = 1;
}
Dois-je préférer l'un à l'autre?
javascript
typescript
class
encapsulation
Matt Bierner
la source
la source
Réponses:
Mot-clé privé
Le mot clé privé dans TypeScript est une annotation de compilation . Il indique au compilateur qu'une propriété ne doit être accessible qu'à l'intérieur de cette classe:
Cependant, la vérification du temps de compilation peut être facilement contournée, par exemple en supprimant les informations de type:
Le
private
mot clé n'est également pas appliqué lors de l'exécutionJavaScript émis
Lors de la compilation de TypeScript en JavaScript, le
private
mot-clé est simplement supprimé:Devient:
De là, vous pouvez voir pourquoi le
private
mot-clé n'offre aucune protection d'exécution: dans le JavaScript généré, c'est juste une propriété JavaScript normale.Champs privés
Les champs privés garantissent que les propriétés restent privées lors de l'exécution :
TypeScript générera également une erreur de temps de compilation si vous essayez d'utiliser un champ privé en dehors d'une classe:
Les champs privés proviennent d'une proposition JavaScript et fonctionnent également en JavaScript normal.
JavaScript émis
Si vous utilisez des champs privés dans TypeScript et ciblez des versions plus anciennes de JavaScript pour votre sortie, telles que
es6
oues2018
, TypeScript essaiera de générer du code qui émule le comportement d'exécution des champs privésSi vous ciblez
esnext
, TypeScript émettra le champ privé:Lequel devrais-je utiliser?
Cela dépend de ce que vous essayez de réaliser.
Le
private
mot-clé est un bon défaut. Il accomplit ce pour quoi il a été conçu et a été utilisé avec succès par les développeurs TypeScript pendant des années. Et si vous avez une base de code existante, vous n'avez pas besoin de changer tout votre code pour utiliser des champs privés. Cela est particulièrement vrai si vous ne ciblez pasesnext
, car le JS que TS émet pour les champs privés peut avoir un impact sur les performances. Gardez également à l'esprit que les champs privés présentent d'autres différences subtiles mais importantes par rapport auprivate
mot cléCependant, si vous devez appliquer la confidentialité d'exécution ou si vous générez du
esnext
JavaScript, vous devez utiliser des champs privés.Gardez également à l'esprit que les conventions organisationnelles / communautaires sur l'utilisation de l'un ou de l'autre évolueront également à mesure que les champs privés se répandront dans les écosystèmes JavaScript / TypeScript.
Autres différences notables
Les champs privés ne sont pas retournés par
Object.getOwnPropertyNames
des méthodes similairesLes champs privés ne sont pas sérialisés par
JSON.stringify
Il y a des cas marginaux importants autour de l'héritage.
TypeScript, par exemple, interdit de déclarer une propriété privée dans une sous-classe avec le même nom qu'une propriété privée dans la superclasse.
Ce n'est pas vrai avec les champs privés:
Une
private
propriété privée de mot-clé sans initialiseur ne générera pas de déclaration de propriété dans le JavaScript émis:Compile vers:
Alors que les champs privés génèrent toujours une déclaration de propriété:
Compile vers (lors du ciblage
esnext
):Lectures complémentaires:
la source
Cas d'utilisation: -
#
champs privésPréface:
#
-privé, privé privé, privé à l'exécutionConfidentialité à la compilation et à l' exécution
#
-Les champs privés fournissent une confidentialité au moment de la compilation et de l' exécution, qui n'est pas "piratable". C'est un mécanisme pour empêcher l'accès à un membre de l'extérieur du corps de classe de quelque manière directe .Héritage de classe sécurisé
#
-Les champs privés ont une portée unique. Les hiérarchies de classes peuvent être implémentées sans écraser accidentellement des propriétés privées de noms égaux.Le compilateur TS émet heureusement une erreur, lorsque les
private
propriétés risquent d'être écrasées (voir cet exemple ). Mais en raison de la nature d'une fonctionnalité au moment de la compilation, tout est encore possible au moment de l'exécution, étant donné que les erreurs de compilation sont ignorées et / ou le code JS émis est utilisé.Bibliothèques externes
Les auteurs de bibliothèque peuvent refactoriser les
#
identifiants privés sans provoquer de changement majeur pour les clients. Les utilisateurs de la bibliothèque de l'autre côté sont protégés contre l'accès aux champs internes.L'API JS omet les
#
champs privésLes fonctions et méthodes JS intégrées ignorent les
#
champs privés. Cela peut entraîner une sélection de propriétés plus prévisible au moment de l'exécution. Exemples:Object.keys
,Object.entries
,JSON.stringify
,for..in
boucle et autres ( exemple de code , voir aussi Matt Bierner réponse ):Cas d'utilisation:
private
mot - cléPréface:
private
mot-clé dans les documents TSAccès à l'API et à l'état de la classe interne (confidentialité au moment de la compilation uniquement)
private
les membres d'une classe sont des propriétés classiques au moment de l'exécution. Nous pouvons utiliser cette flexibilité pour accéder à l'API interne de classe ou à l'état de l'extérieur. Afin de satisfaire les vérifications du compilateur, des mécanismes tels que les assertions de type, l'accès aux propriétés dynamiques ou@ts-ignore
peuvent être utilisés entre autres.Exemple avec assertion de type (
as
/<>
) etany
affectation de variable typée:TS permet même un accès dynamique aux propriétés d'un
private
membre avec un hayon :Où l'accès privé peut-il avoir un sens? (1) des tests unitaires, (2) des situations de débogage / journalisation ou (3) d'autres scénarios de cas avancés avec des classes internes au projet (liste ouverte).
L'accès aux variables internes est un peu contradictoire - sinon vous ne les auriez pas faites
private
en premier lieu. Pour donner un exemple, les tests unitaires sont supposés être des boîtes noires / grises avec des champs privés cachés comme détails d'implémentation. En pratique cependant, il peut y avoir des approches valables d'un cas à l'autre.Disponible dans tous les environnements ES
Les
private
modificateurs TS peuvent être utilisés avec toutes les cibles ES.#
-Les champs privés ne sont disponibles que pourtarget
ES2015
/ES6
ou plus. Dans ES6 +,WeakMap
est utilisé en interne comme implémentation de niveau inférieur (voir ici ). Les#
champs natifs- privés nécessitent actuellementtarget
esnext
.Cohérence et compatibilité
Les équipes peuvent utiliser des directives de codage et des règles de linter pour imposer l'utilisation de
private
comme seul modificateur d'accès. Cette restriction peut aider à la cohérence et éviter toute confusion avec la#
notation de champ privé d'une manière rétrocompatible.Si nécessaire, les propriétés des paramètres (raccourci d'affectation du constructeur) sont un bouchon d'exposition. Ils ne peuvent être utilisés qu'avec des
private
mots clés et il n'est pas encore prévu de les implémenter pour les#
champs privés.Autres raisons
private
peut fournir de meilleures performances d'exécution dans certains cas de mise à niveau inférieur (voir ici ).private
notation par mots clés 😊.Remarque sur les deux
Les deux approches créent une sorte de type nominal ou de marque au moment de la compilation.
En outre, les deux autorisent l'accès inter-instances: une instance de classe
A
peut accéder aux membres privés d'autresA
instances:Sources
la source