115 votes

Pourquoi puis-je accéder aux membres privés de TypeScript alors que je ne devrais pas pouvoir le faire ?

J'étudie l'implémentation des membres privés en TypeScript, et je trouve cela un peu confus. Intellisense ne permet pas d'accéder aux membres privés, mais en JavaScript pur, tout est là. Cela me fait penser que TS n'implémente pas correctement les membres privés. Une idée ?

class Test{
  private member: any = "private member";
}
alert(new Test().member);

5voto

alexanderbird Points 1979

Merci à Sean Feldman pour le lien vers la discussion officielle sur cette question - voir sa réponse pour le lien.

J'ai lu la discussion dont il a fait le lien, et Voici un résumé des points clés :

  • Suggestion : propriétés privées dans le constructeur
    • problèmes : ne peut pas accéder à partir de fonctions prototypes
  • Suggestion : méthodes privées dans le constructeur
    • problèmes : comme pour les propriétés, mais vous perdez l'avantage en termes de performances que représente la création d'une fonction une fois par classe dans le prototype ; à la place, vous créez une copie de la fonction pour chaque instance.
  • Suggestion : ajouter un modèle pour abstraire l'accès aux propriétés et renforcer la visibilité
    • problèmes : surcharge importante des performances ; TypeScript est conçu pour les grandes applications
  • Suggestion : TypeScript englobe déjà les définitions des méthodes du constructeur et du prototype dans une fermeture ; placez-y les méthodes et les propriétés privées.
    • des problèmes pour mettre des propriétés privées dans cette fermeture : elles deviennent des variables statiques ; il n'y en a pas une par instance
    • des problèmes pour mettre des méthodes privées dans cette fermeture : ils n'ont pas accès à this sans une sorte de solution de contournement
  • Suggestion : mangle automatiquement les noms des variables privées
    • des contre-arguments : c'est une convention de dénomination, pas une construction du langage. Emmêlez-le vous-même
  • Suggestion : Annoter les méthodes privées avec @private Ainsi, les mineurs qui reconnaissent cette annotation peuvent effectivement minifier les noms de méthodes.
    • Aucun contre-argument significatif à celui-ci

Contre-arguments généraux à l'ajout du support de la visibilité dans le code émis :

  • Le problème est que JavaScript lui-même n'a pas de modificateurs de visibilité - ce n'est pas le problème de TypeScript.
  • il existe déjà un modèle établi dans la communauté JavaScript : préfixer les propriétés et méthodes privées par un trait de soulignement, ce qui signifie "procédez à vos propres risques".
  • lorsque les concepteurs de TypeScript ont dit que les propriétés et méthodes véritablement privées ne sont pas "possibles", ils voulaient dire "pas possible dans le cadre de nos contraintes de conception", spécifiquement :
    • Le JS émis est idiomatique
    • Le modèle de base est minimal
    • Pas de surcharge supplémentaire par rapport au JS OOP normal.

1voto

Caspian Canuck Points 371

Je me rends compte qu'il s'agit d'une discussion plus ancienne, mais il pourrait être utile de partager ma solution au problème des variables et méthodes supposées privées dans un TypeScript qui "fuient" dans l'interface publique de la classe JavaScript compilée.

Pour moi, ce problème est purement cosmétique, c'est-à-dire qu'il s'agit de l'encombrement visuel lorsqu'une variable d'instance est visualisée dans DevTools. Ma solution consiste à regrouper les déclarations privées à l'intérieur d'une autre classe qui est ensuite instanciée dans la classe principale et affectée à une variable d'instance. private (mais toujours visible publiquement en JS) variable avec un nom comme __ (double soulignement).

Ejemplo:

class Privates {
    readonly DEFAULT_MULTIPLIER = 2;
    foo: number;
    bar: number;

    someMethod = (multiplier: number = this.DEFAULT_MULTIPLIER) => {
        return multiplier * (this.foo + this.bar);
    }

    private _class: MyClass;

    constructor(_class: MyClass) {
        this._class = _class;
    }
}

export class MyClass {
    private __: Privates = new Privates(this);

    constructor(foo: number, bar: number, baz: number) {
        // assign private property values...
        this.__.foo = foo;
        this.__.bar = bar;

        // assign public property values...
        this.baz = baz;
    }

    baz: number;

    print = () => {
        console.log(`foo=${this.__.foo}, bar=${this.__.bar}`);
        console.log(`someMethod returns ${this.__.someMethod()}`);
    }
}

let myClass = new MyClass(1, 2, 3);

Lorsque le myClass est visualisée dans DevTools, au lieu de voir tous ses membres "privés" mélangés avec les membres réellement publics (ce qui peut devenir très désordonné visuellement dans un code réel correctement remanié), vous les voyez soigneusement regroupés à l'intérieur de l'instance effondrée __ propriété :

enter image description here

0voto

Muhammad Awais Points 1735

En TypeScript, les fonctions privées ne sont accessibles qu'à l'intérieur de la classe. Comme

enter image description here

Et une erreur s'affichera lorsque vous tenterez d'accéder à un membre privé. Voici l'exemple :

enter image description here

Note : Cela fonctionnera bien avec javascript et les deux fonctions sont accessibles à l'extérieur.

0voto

user1102051 Points 152

Voici une approche réutilisable pour ajouter des propriétés privées appropriées :

/**
 * Implements proper private properties.
 */
export class Private<K extends object, V> {

    private propMap = new WeakMap<K, V>();

    get(obj: K): V {
        return this.propMap.get(obj)!;
    }

    set(obj: K, val: V) {
        this.propMap.set(obj, val);
    }
}

Disons que vous avez une classe Client quelque part qui a besoin de deux propriétés privées :

  • prop1: string
  • prop2: number

Voici comment le mettre en œuvre :

// our private properties:
interface ClientPrivate {
    prop1: string;
    prop2: number;
}

// private properties for all Client instances:
const pp = new Private<Client, ClientPrivate>();

class Client {
    constructor() {
        pp.set(this, {
            prop1: 'hello',
            prop2: 123
        });
    }

    someMethod() {
        const privateProps = pp.get(this);

        const prop1 = privateProps.prop1;
        const prop2 = privateProps.prop2;
    }
}

Et si tout ce dont vous avez besoin est une seule propriété privée, alors cela devient encore plus simple, parce que vous n'aurez pas besoin de définir une quelconque ClientPrivate dans ce cas.

Il est intéressant de noter que, pour la plupart, la classe Private offre simplement une signature bien lisible, alors que l'utilisation directe de l'option WeakMap ne le fait pas.

0voto

Sean Amarasinghe Points 325

En résumé - Le système de classification des caractères envoie un message d'avertissement. Mais le private est une caractéristique spécifique au système de types, donc il disparaîtra au moment de l'exécution.

Lisez un article que j'ai écrit sur l'accès aux variables privées TypeScript ici : https://szaranger.medium.com/stop-relying-on-private-to-hide-variables-in-typescript-3c45d25a58d0

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X