ottenere e impostare in TypeScript


660

Sto cercando di creare il metodo get e set per una proprietà:

private _name: string;

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

Qual è la parola chiave per impostare un valore?


12
Il carattere di sottolineatura e PascalCase sono in conflitto con le linee guida per la codifica Typescript: github.com/Microsoft/TypeScript/wiki/Coding-guidelines
Niels Steenbeek,

2
Ciao @NielsSteenbeek - seguendo le linee guida per i contributori TypeScript con proprietà e campi di supporto potresti finire con un conflitto di nomi. Qual è l'approccio suggerito?
Giordania,

Forse: typescript private name: string; getName() { get: { return this.name; } set: { this.name = ???; } }
Giordania,

7
Meno male che le linee guida per la codifica di Typescript sono poco attraenti. Li userei solo con la coercizione (ad es. Sono stato pagato per farlo).
Thomas Eding,

15
@NielsSteenbeek: hai letto quel documento? "Questa NON è una linea guida prescrittiva per la comunità TypeScript"
Jonathan Cast

Risposte:


1084

TypeScript utilizza una sintassi getter / setter simile ad ActionScript3.

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

Questo produrrà questo JavaScript, usando la Object.defineProperty()funzione ECMAScript 5 .

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;
})();

Quindi per usarlo,

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

Tuttavia, per poterlo utilizzare, è necessario assicurarsi che il compilatore TypeScript abbia come destinazione ECMAScript5. Se stai eseguendo il compilatore della riga di comando, usa --targetflag in questo modo;

tsc --target ES5

Se si utilizza Visual Studio, è necessario modificare il file di progetto per aggiungere il flag alla configurazione per lo strumento di compilazione TypeScriptCompile. Puoi vederlo qui :

Come suggerisce @DanFromGermany di seguito, se stai semplicemente leggendo e scrivendo una proprietà locale come foo.bar = true, avere una coppia setter e getter è eccessivo. Puoi sempre aggiungerli in un secondo momento se devi fare qualcosa, come la registrazione, ogni volta che la proprietà viene letta o scritta.


59
Bella risposta. Inoltre, notare che, a differenza di C #, le proprietà non sono attualmente virtualizzate in TypeScript (v0.9.5). Quando si implementa "get bar ()" in una classe derivata, si sta sostituendo "get bar ()" nel padre. Le implicazioni includono la possibilità di chiamare l'accessor della classe base dall'accessor derivato. Questo vale solo per le proprietà: i metodi si comportano come ci si potrebbe aspettare. Si veda la risposta da SteveFenton qui: stackoverflow.com/questions/13121431/...
David Cuccia

14
Sono leggermente confuso riguardo al carattere di sottolineatura. La convenzione dattiloscritta dice di non usare i trattini bassi per le variabili private? Ma in questo caso, dobbiamo usare i trattini bassi - o avremo un conflitto tra il "bar" privato e pubblico
Kokodoko

4
Utilizzare il trattino basso è una preferenza personale per le proprietà private. Tuttavia, credo che tu abbia ragione nel desiderare che la proprietà abbia un nome diverso rispetto ai metodi getter / setter.
Ezward,

3
Perché usi myFoo.bar = trueinvece di myFoo.bar(true);o myFoo.setBar(true);??
Daniel W.,

6
@DanFromGermany Una proprietà è "zucchero sintattico" per una coppia di metodi "get" e "set". Microsoft ha originato il concetto di una proprietà con Visual Basic e l'ha trasferito in linguaggi .NET come C # e VB.NET. Ad esempio, vedere Proprietà (Guida per programmatori C #) . Le proprietà semplificano l'accesso allo stato di un oggetto ed (a mio avviso) eliminano la "rumorosità" di dover affrontare le coppie di metodi "get / set". (O a volte solo "ottenere" metodi dove si desidera l'immutabilità.)
DavidRR

113

Ezward ha già fornito una buona risposta, ma ho notato che uno dei commenti chiede come viene utilizzato. Per le persone come me che si imbattono in questa domanda, ho pensato che sarebbe utile avere un link alla documentazione ufficiale su getter e setter sul sito Web Typescript, come spiegato bene, si spera che rimanga sempre aggiornato poiché le modifiche sono fatto e mostra un esempio di utilizzo:

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

In particolare, per coloro che non hanno familiarità con esso, si noti che non si incorpora la parola "get" in una chiamata a un getter (e allo stesso modo per i setter):

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

Dovresti semplicemente fare questo:

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

dato un corso come:

class foo {
  private _bar:boolean = false;

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

quindi verrà chiamato il getter "bar" per la proprietà privata "_bar".


Se volevo sostituire una var pubblica a livello di classe con una proprietà, è una sostituzione diretta che posso mettere in atto e non preoccuparmi? In altre parole, se test di regressione un accessor e un setter, posso ritenerlo un successo? Oppure ci sono casi in cui non funzionerà esattamente come un var e devo testare tutti i 100 posti che usano questo var / prop?
Adam Plocher,

Mi chiedevo se ci fosse una soluzione alternativa per l'utilizzo di caratteri di sottolineatura per distinguere il nome della proprietà dai metodi getter o setter. In un corso che stavo facendo hanno detto che i caratteri di sottolineatura non erano preferiti ma non davano un'alternativa.
cham

1
@cham Non devi usare i trattini bassi qui ... Puoi chiamare la variabile privata notbar se vuoi.
Robert McKee,

59

Ecco un esempio funzionante che dovrebbe indirizzarti nella giusta direzione:

class Foo {
    _name;

    get Name() {
        return this._name;
    }

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

Getter e setter in JavaScript sono funzioni normali. Il setter è una funzione che accetta un parametro il cui valore è il valore impostato.


30
Per essere chiari, non è necessario che la proprietà, il getter e il setter siano static.
Drew Noakes,

1
i riferimenti alle variabili sono comunque statici. Foo._namedovrebbe essere sostituito conthis._name
Johannes,

6

Puoi scrivere questo

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;
    } 

}

2
Perché il pubblico nel costruttore?
MuriloKunze,

17
Sì, non può avere pubblico nel costruttore in questo codice. publicqui definisce membri duplicati.
Orad,

2
Puoi scriverlo ma non lo compilerai
Justin

3

TS offre getter e setter che consentono alle proprietà degli oggetti di avere un maggiore controllo sul modo in cui sono accessibili (getter) o aggiornati (setter) all'esterno dell'oggetto. Invece di accedere direttamente o aggiornare la proprietà viene chiamata una funzione proxy.

Esempio:

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';  

1

È molto simile alla creazione di metodi comuni, basta inserire la parola chiave riservata geto setall'inizio.

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();

In questo caso puoi saltare il tipo restituito get getMethod1() {

    get getMethod1() {
        return this._name;
    }

1

Penso che probabilmente capisco perché è così confuso. Nel tuo esempio, volevamo getter e setter per _name. Ma ci riusciamo creando getter e setter per una variabile di classe non correlataName .

Considera questo:

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

Il codice sopra fa quanto segue:

  1. gete setcrea getter e setter per yourCarTiresCount( non pertiresCount ).

Il getter è:

function() {
    return this.tiresCount ;
}

e il setter è:

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

Cioè, ogni volta che lo facciamo new Car().yourCarTiresCount, getter corre. E per ogni new Car().yourCarTiresCount('7')setter corre.

  1. Crea indirettamente getter, ma non il setter, per il privato tireCount.

0

Se stai cercando il modo di usare get e set su qualsiasi oggetto (non una classe) Proxy può essere 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

Nota: tenere presente che si tratta di una nuova API non supportata e di un polifill richiesto per i browser meno recenti


-6

Se stai lavorando con moduli TypeScript e stai provando ad aggiungere un getter che viene esportato, puoi fare qualcosa del genere:

// 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;
    },
});

Quindi, in un altro file hai:

import * as dataStore from "./dataStore"
console.log(dataStore.myData); // "my data"

8
È un consiglio terribile. In particolare, non thisdeve essere definito nell'ambito di livello superiore di un modulo. Potresti exportsinvece usarlo ma non dovresti farlo affatto poiché è praticamente garantito che causi problemi di compatibilità
Aluan Haddad,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.