obtenir et définir en TypeScript

660

J'essaie de créer une méthode get et set pour une propriété:

private _name: string;

Name() {
    get:
    {
        return this._name;
    }
    set:
    {
        this._name = ???;
    }
}

Quel est le mot clé pour définir une valeur?

MuriloKunze
la source
12
Le soulignement et PascalCase sont en conflit avec les lignes directrices de codage Typescript: github.com/Microsoft/TypeScript/wiki/Coding-guidelines
Niels Steenbeek
2
Salut @NielsSteenbeek - en suivant les directives des contributeurs TypeScript avec les propriétés et les champs de sauvegarde, vous vous retrouveriez avec un conflit de nom. Quelle est l'approche suggérée?
Jordanie
Peut-être: typescript private name: string; getName() { get: { return this.name; } set: { this.name = ???; } }
Jordan
7
Heureusement, ces directives de codage Typescript sont assez peu attrayantes. Je ne les utiliserais que sous la contrainte (par exemple, j'étais payé pour le faire).
Thomas Eding
15
@NielsSteenbeek: avez-vous lu ce document? "Ce n'est PAS une directive normative pour la communauté TypeScript"
Jonathan Cast

Réponses:

1084

TypeScript utilise une syntaxe getter / setter semblable à ActionScript3.

class foo {
    private _bar: boolean = false;
    get bar(): boolean {
        return this._bar;
    }
    set bar(value: boolean) {
        this._bar = value;
    }
}

Cela produira ce JavaScript, en utilisant la fonction ECMAScript 5 Object.defineProperty().

var foo = (function () {
    function foo() {
        this._bar = false;
    }
    Object.defineProperty(foo.prototype, "bar", {
        get: function () {
            return this._bar;
        },
        set: function (value) {
            this._bar = value;
        },
        enumerable: true,
        configurable: true
    });
    return foo;
})();

Donc, pour l'utiliser,

var myFoo = new foo();
if(myFoo.bar) {         // calls the getter
    myFoo.bar = false;  // calls the setter and passes false
}

Cependant, pour pouvoir l'utiliser, vous devez vous assurer que le compilateur TypeScript cible ECMAScript5. Si vous exécutez le compilateur de ligne de commande, utilisez un --targetindicateur comme celui-ci;

tsc --target ES5

Si vous utilisez Visual Studio, vous devez modifier votre fichier de projet pour ajouter l'indicateur à la configuration de l'outil de génération TypeScriptCompile. Vous pouvez le voir ici :

Comme @DanFromGermany le suggère ci-dessous, si vous lisez et écrivez simplement une propriété locale comme foo.bar = true, alors avoir une paire setter et getter est exagéré. Vous pouvez toujours les ajouter ultérieurement si vous avez besoin de faire quelque chose, comme la journalisation, chaque fois que la propriété est lue ou écrite.

Ezward
la source
59
Bonne réponse. Notez également que, contrairement à C #, les propriétés ne sont pas actuellement virtualisées dans TypeScript (v0.9.5). Lorsque vous implémentez "get bar ()" dans une classe dérivée, vous remplacez "get bar ()" dans le parent. Les implications incluent l'impossibilité d'appeler l'accesseur de classe de base à partir de l'accesseur dérivé. Cela n'est vrai que pour les propriétés - les méthodes se comportent comme vous pouvez vous y attendre. Voir la réponse de SteveFenton ici: stackoverflow.com/questions/13121431/…
David Cuccia
14
Je suis légèrement confus au sujet du trait de soulignement. La convention de dactylographie dit de ne pas utiliser de soulignements pour les variables privées? Mais dans ce cas, nous devons utiliser des
traits de soulignement
4
Utiliser le trait de soulignement est une préférence personnelle pour les propriétés privées. Cependant, je pense que vous avez raison en ce que nous voulons que la propriété ait un nom différent de celui des méthodes getter / setter.
Ezward
3
Pourquoi utilisez-vous myFoo.bar = trueau lieu de myFoo.bar(true);ou myFoo.setBar(true);??
Daniel
6
@DanFromGermany Une propriété est un "sucre syntaxique" pour une paire de méthodes "get" et "set". Microsoft a créé le concept de propriété avec Visual Basic et l'a transféré aux langages .NET tels que C # et VB.NET. Par exemple, consultez Propriétés (Guide de programmation C #) . Les propriétés simplifient l'accès à l'état d'un objet et (à mon avis) éliminent le "bruit" d'avoir à gérer des paires de méthodes "get / set". (Ou parfois seulement "obtenir" des méthodes où l'immuabilité est souhaitée.)
DavidRR
113

Ezward a déjà fourni une bonne réponse, mais j'ai remarqué que l'un des commentaires demande comment il est utilisé. Pour les gens comme moi qui tombent sur cette question, j'ai pensé qu'il serait utile d'avoir un lien vers la documentation officielle sur les getters et setters sur le site Web de Typescript car cela l'explique bien, nous espérons toujours rester à jour car les changements sont fait, et montre un exemple d'utilisation:

http://www.typescriptlang.org/docs/handbook/classes.html

En particulier, pour ceux qui ne le connaissent pas, notez que vous n'incorporez pas le mot «get» dans un appel à un getter (et de même pour les setters):

var myBar = myFoo.getBar(); // wrong    
var myBar = myFoo.get('bar');  // wrong

Vous devez simplement faire ceci:

var myBar = myFoo.bar;  // correct (get)
myFoo.bar = true;  // correct (set) (false is correct too obviously!)

étant donné une classe comme:

class foo {
  private _bar:boolean = false;

  get bar():boolean {
    return this._bar;
  }
  set bar(theBar:boolean) {
    this._bar = theBar;
  }
}

alors le getter 'bar' de la propriété privée '_bar' sera appelé.

TornadoAli
la source
Si je voulais remplacer un var public de niveau classe par une propriété, est-ce un remplacement direct que je peux mettre en place et ne pas m'en inquiéter? En d'autres termes, si je teste en régression un accesseur et un setter, puis-je le considérer comme un succès? Ou y a-t-il des cas où cela ne fonctionnera pas exactement de la même manière qu'un var et que je dois tester les 100 emplacements qui utilisent ce var / prop?
Adam Plocher
Je me demandais s'il y avait une solution de contournement pour l'utilisation de soulignements pour distinguer le nom de la propriété des méthodes getter ou setter. Dans un cours que je faisais, ils ont dit que les soulignés n'étaient pas préférés mais ne donnaient pas d'alternative.
cham
1
@cham Vous n'avez pas besoin d'utiliser de soulignements ici ... Vous pouvez appeler la variable privée notbar si vous le souhaitez.
Robert McKee
59

Voici un exemple de travail qui devrait vous orienter dans la bonne direction:

class Foo {
    _name;

    get Name() {
        return this._name;
    }

    set Name(val) {
        this._name = val;
    }
}

Les getters et setters en JavaScript ne sont que des fonctions normales. Le setter est une fonction qui prend un paramètre dont la valeur est la valeur en cours de définition.

Brian Terlson
la source
30
Pour être clair, il n'est pas nécessaire que la propriété, getter et setter soit static.
Drew Noakes
1
les références des variables restent cependant statiques. Foo._namedevrait être remplacé parthis._name
Johannes
6

Tu peux écrire ça

class Human {
    private firstName : string;
    private lastName : string;

    constructor (
        public FirstName?:string, 
        public LastName?:string) {

    }

    get FirstName() : string {
        console.log("Get FirstName : ", this.firstName);
        return this.firstName;
    }
    set FirstName(value : string) {
        console.log("Set FirstName : ", value);
        this.firstName = value;
    } 

    get LastName() : string {
        console.log("Get LastName : ", this.lastName);
        return this.lastName;
    }
    set LastName(value : string) {
        console.log("Set LastName : ", value);
        this.lastName = value;
    } 

}
k33g_org
la source
2
Pourquoi le public en constructeur?
MuriloKunze
17
Oui, ne peut pas avoir public dans constructeur dans ce code. publicdéfinit ici les membres en double.
orad
2
Vous pouvez l'écrire mais il ne compilera pas
Justin
3

TS propose des getters et setters qui permettent aux propriétés d'objet d'avoir plus de contrôle sur la façon dont elles sont accédées (getter) ou mises à jour (setter) en dehors de l'objet. Au lieu d'accéder directement à la propriété ou de la mettre à jour, une fonction proxy est appelée.

Exemple:

class Person {
    constructor(name: string) {
        this._name = name;
    }

    private _name: string;

    get name() {
        return this._name;
    }

    // first checks the length of the name and then updates the name.
    set name(name: string) {
        if (name.length > 10) {
            throw new Error("Name has a max length of 10");
        }

        this._name = name;  
    }

    doStuff () {
        this._name = 'foofooooooofoooo';
    }


}

const person = new Person('Willem');

// doesn't throw error, setter function not called within the object method when this._name is changed
person.doStuff();  

// throws error because setter is called and name is longer than 10 characters
person.name = 'barbarbarbarbarbar';  
Willem van der Veen
la source
1

C'est très similaire à la création de méthodes courantes, il suffit de mettre le mot-clé réservé getou setau début.

class Name{
    private _name: string;

    getMethod(): string{
        return this._name;
    }

    setMethod(value: string){
        this._name = value
    }

    get getMethod1(): string{
        return this._name;
    }

    set setMethod1(value: string){
        this._name = value
    }
}

class HelloWorld {

    public static main(){

        let test = new Name();

        test.setMethod('test.getMethod() --- need ()');
            console.log(test.getMethod());

        test.setMethod1 = 'test.getMethod1 --- no need (), and used = for set ';
            console.log(test.getMethod1);
    }
}
HelloWorld.main();

Dans ce cas, vous pouvez ignorer le type de retour dans get getMethod1() {

    get getMethod1() {
        return this._name;
    }
Angel Angel
la source
1

Je pense que je comprends probablement pourquoi c'est si déroutant. Dans votre exemple, nous voulions des getters et setters _name. Mais nous y parvenons en créant des getters et setters pour une variable de classe indépendante Name.

Considère ceci:

class Car{
    private tiresCount = 4;
    get yourCarTiresCount(){
        return this.tiresCount ;
    }
    set yourCarTiresCount(count) {
        alert('You shouldn't change car tire count')
    }
}

Le code ci-dessus fait ce qui suit:

  1. getet setcréer getter et setter pour yourCarTiresCount( pas pourtiresCount ).

Le getter est:

function() {
    return this.tiresCount ;
}

et le passeur est:

function(count) {
    alert('You shouldn't change car tire count');
}

Ce qui signifie, chaque fois que nous le faisons new Car().yourCarTiresCount, getter court. Et pour chaque new Car().yourCarTiresCount('7')setter s'exécute.

  1. Créez indirectement getter, mais pas le setter, pour privé tireCount.
dasfdsa
la source
0

Si vous cherchez un moyen d'utiliser get et set sur n'importe quel objet (pas une classe) Proxy peut être utile: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Proxy

const target = {
  message1: "hello",
  message2: "everyone"
};

const handler3 = {
  get: function (target, prop, receiver) {
    if (prop === "message2") {
      return "world";
    }
    return Reflect.get(...arguments);
  },
};

const proxy3 = new Proxy(target, handler3);

console.log(proxy3.message1); // hello
console.log(proxy3.message2); // world

Remarque: sachez qu'il s'agit d'une nouvelle API non prise en charge et polifill requis pour les anciens navigateurs

devi
la source
-6

Si vous travaillez avec des modules TypeScript et essayez d'ajouter un getter qui est exporté, vous pouvez faire quelque chose comme ceci:

// dataStore.ts
export const myData: string = undefined;  // just for typing support
let _myData: string;  // for memoizing the getter results

Object.defineProperty(this, "myData", {
    get: (): string => {
        if (_myData === undefined) {
            _myData = "my data";  // pretend this took a long time
        }

        return _myData;
    },
});

Ensuite, dans un autre fichier, vous avez:

import * as dataStore from "./dataStore"
console.log(dataStore.myData); // "my data"
cjbarth
la source
8
C'est un conseil terrible. En particulier, thisdoit être non défini au niveau supérieur d'un module. Vous pouvez utiliser à la exportsplace, mais vous ne devriez pas le faire du tout car il est pratiquement garanti de causer des problèmes de compatibilité
Aluan Haddad