Menu

Modificateurs d'accès TypeScript : public, private, protected

TypeScript a trois modificateurs d'accès, public, private et protected, plus readonly. Découvrez ce que chacun autorise, pourquoi le private de TypeScript est une vérification à la compilation alors que les champs #private de JavaScript sont imposés à l'exécution, et lequel choisir.

Cette page contient des éditeurs exécutables - modifiez, exécutez et voyez la sortie instantanément.

TypeScript a trois modificateurs d'accès pour les membres de classe : public (par défaut), protected et private. Ils contrôlent où un membre peut être utilisé, et le compilateur signale tout accès depuis un endroit interdit.

La dernière ligne est une erreur de compilation, mais regardez ce qu'elle a affiché une fois exécutée malgré tout : 123-45-6789. C'est le fait le plus important de cette page, et la section sur private l'explique.

Ce qu'autorise chaque modificateur

ModificateurDans la classeDans une sous-classeDepuis l'extérieurImposé à l'exécution
public (par défaut)ouiouiouirien à imposer
protectedouiouinonnon
privateouinonnonnon
#name (JavaScript)ouinonnonoui
readonlylecture, et écriture dans le constructeurlecturelecturenon

Les modificateurs s'appliquent aux champs, aux méthodes, aux getters et setters, aux constructeurs et aux propriétés de paramètres (constructor(private id: string)). Écrire public est facultatif, et beaucoup de bases de code l'omettent.

private est une vérification à la compilation

TypeScript efface private avec le reste des types. La classe compilée contient une propriété ordinaire, donc tout ce qui ne passe pas par le vérificateur de types la voit : les appelants en JavaScript pur, JSON.stringify, Object.keys, et même la notation à crochets de TypeScript, autorisée comme échappatoire volontaire.

Cela convient à ce pour quoi private existe : indiquer aux autres développeurs (et à votre éditeur) qu'un membre est un détail d'implémentation. Ce n'est pas une frontière de sécurité, et un champ private finira dans les logs et les réponses JSON si vous ne le retirez pas vous-même.

Les champs #private : imposés à l'exécution

JavaScript a ses propres champs privés, écrits avec #. Le moteur les impose : hors de la classe, obj.#field n'est même pas une syntaxe valide, et le champ n'apparaît ni dans Object.keys, ni dans JSON.stringify, ni dans console.log.

Écrire s.#token hors de la classe provoque l'erreur TS18013 (Property '#token' is not accessible outside class 'Session' because it has a private identifier), et contrairement au cas de private, il n'existe aucun contournement à l'exécution non plus. Voir champs privés en JavaScript pour les règles d'exécution.

private ou #private : lequel utiliser

private x#x
Vérifié parle compilateurle moteur JavaScript
Visible par Object.keys / JSON.stringifyouinon
Accès par crochets obj["x"]autoriséimpossible
Une sous-classe peut déclarer son propre xnon, conflitoui, chaque classe a son propre #x
Copié par un étalement { ...obj }ouinon
Syntaxe sur les méthodesprivate helper()#helper()

Utilisez #private quand les données doivent rester privées à l'exécution (tokens, état interne auquel les utilisateurs d'une bibliothèque ne doivent pas toucher) ou quand vous voulez que JSON.stringify les ignore. Utilisez private quand le but est seulement une API publique propre, quand un framework doit lire le champ par réflexion, ou pour suivre le style existant d'une base de code. Ne combinez pas les deux : private #x provoque l'erreur TS18010 (An accessibility modifier cannot be used with a private identifier).

protected et les sous-classes

Un membre protected est disponible dans la classe et dans toute classe qui l'étend, mais pas sur les instances depuis l'extérieur.

Une règle surprend. Dans Polygon, vous pouvez lire sides sur this ou sur un autre Polygon, mais pas sur un simple Shape reçu en paramètre : other.sides avec other: Shape provoque l'erreur TS2446 (Property 'sides' is protected and only accessible through an instance of class 'Polygon'. This is an instance of class 'Shape'.). Une sous-classe ne peut atteindre les membres protected que des objets qui appartiennent à sa propre branche de la hiérarchie.

Une sous-classe peut rendre public un membre protected en le redéclarant, mais elle ne peut pas rendre protected ou private un membre public. Redéclarez-le avec un initialiseur (public override sides = 6) ou uniquement en tant que type (declare public sides: number). Un simple public sides: number; est refusé avec TS2564 et TS2612, car avec les champs de classe modernes il remettrait la valeur héritée à undefined après le retour de super().

readonly

readonly bloque la réassignation après la construction. Le champ peut être défini dans sa déclaration ou dans le constructeur ; toute assignation ultérieure provoque l'erreur TS2540.

Deux limites apparaissent ici. readonly est superficiel : le tableau ne peut pas être remplacé, mais son contenu peut changer (typez-le readonly string[] pour bloquer push). Et comme private, il disparaît à l'exécution : l'assignation refusée par le compilateur s'est donc quand même exécutée. Pour une valeur qui ne doit pas changer à l'exécution, utilisez Object.freeze ou un getter sans setter. La page readonly présente Readonly<T> et les tableaux readonly.

readonly se combine avec les modificateurs d'accès : private readonly cache = new Map<string, number>() est un motif courant pour un champ interne jamais réassigné.

Erreurs fréquentes

  • Considérer private comme une sécurité. Il disparaît à l'exécution. Utilisez #field pour les données qui doivent rester cachées, et n'envoyez jamais un objet contenant des secrets directement à JSON.stringify.
  • Écrire public partout. C'est la valeur par défaut ; l'ajouter ne change rien.
  • Utiliser protected pour tout ce qui est « interne ». Si aucune sous-classe n'en a besoin, private garde la surface plus réduite.
  • Attendre de readonly qu'il gèle les données imbriquées. Il empêche seulement la réassignation de la propriété elle-même.

Questions fréquentes

Quels sont les modificateurs d'accès en TypeScript ?

public (par défaut : accessible partout), protected (dans la classe et ses sous-classes) et private (dans la classe uniquement). readonly est un modificateur distinct qui bloque la réassignation après le constructeur et se combine avec chacun des trois.

Quelle est la différence entre private et #private en TypeScript ?

private n'est vérifié que par le compilateur ; le JavaScript émis contient une propriété ordinaire, donc obj["secret"], JSON.stringify et Object.keys la voient toujours. #secret est un champ privé JavaScript : l'environnement d'exécution l'impose, et le code extérieur à la classe ne peut pas du tout le lire.

private est-il vraiment privé en TypeScript ?

Seulement à la compilation. Après la compilation, le champ est une propriété normale que n'importe quel code JavaScript peut lire. TypeScript autorise même l'accès par crochets (obj["field"]) aux membres privés comme échappatoire. Utilisez #field quand la confidentialité doit tenir à l'exécution.

Quelle est la différence entre protected et private en TypeScript ?

Un membre private n'est visible que dans la classe qui le déclare. Un membre protected est aussi visible dans les sous-classes. Aucun des deux n'est accessible sur une instance depuis l'extérieur de la hiérarchie de classes.

Peut-on modifier une propriété readonly en TypeScript ?

Une propriété readonly peut être assignée dans sa déclaration ou dans le constructeur, et nulle part ailleurs (sinon TS2540). Elle est superficielle : un readonly tags: string[] ne peut pas être remplacé, mais tags.push() fonctionne toujours. Utilisez readonly string[] pour bloquer cela aussi.

Coddy programming languages illustration

Apprendre à coder avec Coddy

COMMENCER