Holen Sie sich und setzen Sie in TypeScript

656

Ich versuche, eine get- und set-Methode für eine Eigenschaft zu erstellen:

private _name: string;

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

Wie lautet das Schlüsselwort zum Festlegen eines Werts?

MuriloKunze
quelle
12
Der Unterstrich und PascalCase widersprechen den Typescript-Codierungsrichtlinien: github.com/Microsoft/TypeScript/wiki/Coding-guidelines
Niels Steenbeek
2
Hallo @NielsSteenbeek - Wenn Sie die Richtlinien für TypeScript-Mitwirkende mit Eigenschaften und Hintergrundfeldern befolgen, kommt es zu einem Namenskonflikt. Was ist der vorgeschlagene Ansatz?
Jordanien
Vielleicht: typescript private name: string; getName() { get: { return this.name; } set: { this.name = ???; } }
Jordanien
7
Gut, dass diese Typescript-Codierungsrichtlinien ziemlich unattraktiv sind. Ich würde sie nur unter Zwang benutzen (zB wurde ich dafür bezahlt).
Thomas Eding
14
@NielsSteenbeek: Hast du das Dokument gelesen? "Dies ist KEINE Richtlinie für die TypeScript-Community"
Jonathan Cast

Antworten:

1079

TypeScript verwendet eine Getter / Setter-Syntax, die ActionScript3 ähnelt.

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

Dadurch wird dieses JavaScript mithilfe der ECMAScript 5- Object.defineProperty()Funktion erstellt.

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

Also, um es zu benutzen,

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

Um es überhaupt verwenden zu können, müssen Sie jedoch sicherstellen, dass der TypeScript-Compiler auf ECMAScript5 abzielt. Wenn Sie den Befehlszeilen-Compiler ausführen, verwenden Sie das folgende --targetFlag.

tsc --target ES5

Wenn Sie Visual Studio verwenden, müssen Sie Ihre Projektdatei bearbeiten, um der Konfiguration für das TypeScriptCompile-Build-Tool das Flag hinzuzufügen. Das können Sie hier sehen :

Wie @DanFromGermany unten vorschlägt, foo.bar = trueist es übertrieben, ein Setter-Getter-Paar zu haben , wenn Sie einfach eine lokale Eigenschaft wie lesen und schreiben . Sie können sie später jederzeit hinzufügen, wenn Sie etwas tun müssen, z. B. Protokollierung, wenn die Eigenschaft gelesen oder geschrieben wird.

Ezward
quelle
59
Gute Antwort. Beachten Sie außerdem, dass Eigenschaften im Gegensatz zu C # derzeit in TypeScript (v0.9.5) nicht virtualisiert sind. Wenn Sie "get bar ()" in einer abgeleiteten Klasse implementieren, ersetzen Sie "get bar ()" im übergeordneten Element. Zu den Implikationen gehört, dass der Basisklassen-Accessor nicht vom abgeleiteten Accessor aufgerufen werden kann. Dies gilt nur für Eigenschaften - Methoden verhalten sich wie erwartet. Siehe Antwort von SteveFenton hier: stackoverflow.com/questions/13121431/…
David Cuccia
14
Ich bin etwas verwirrt über den Unterstrich. Die Typoskript-Konvention besagt, dass keine Unterstriche für private Variablen verwendet werden sollen. Aber in diesem Fall müssen wir Unterstriche verwenden - oder wir bekommen einen Konflikt zwischen der privaten und öffentlichen "Bar"
Kokodoko
4
Verwenden Sie den Unterstrich ist eine persönliche Präferenz für private Immobilien. Ich glaube jedoch, dass Sie Recht haben, dass die Eigenschaft einen anderen Namen haben soll als die Getter / Setter-Methoden.
Ezward
3
Warum verwenden Sie myFoo.bar = trueanstelle von myFoo.bar(true);oder myFoo.setBar(true);?
Daniel W.
6
@DanFromGermany Eine Eigenschaft ist "syntaktischer Zucker" für ein Paar von "get" - und "set" -Methoden. Microsoft hat das Konzept einer Eigenschaft mit Visual Basic erstellt und auf .NET-Sprachen wie C # und VB.NET übertragen. Siehe beispielsweise Eigenschaften (C # -Programmierhandbuch) . Eigenschaften vereinfachen den Zugriff auf den Status eines Objekts und beseitigen (meiner Meinung nach) das "Rauschen", das mit "get / set" -Methodenpaaren zu tun hat. (Oder manchmal nur "Get" -Methoden, bei denen Unveränderlichkeit erwünscht ist.)
DavidRR
112

Ezward hat bereits eine gute Antwort gegeben, aber ich habe festgestellt, dass in einem der Kommentare gefragt wird, wie es verwendet wird. Für Leute wie mich, die über diese Frage stolpern, hielt ich es für nützlich, einen Link zur offiziellen Dokumentation über Getter und Setter auf der Typescript-Website zu haben, da dies dies gut erklärt und hoffentlich immer auf dem neuesten Stand bleibt, wenn Änderungen vorgenommen werden gemacht und zeigt Beispielverwendung:

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

Beachten Sie insbesondere für diejenigen, die nicht damit vertraut sind, dass Sie das Wort "get" nicht in einen Aufruf an einen Getter einbinden (und ähnlich für Setter):

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

Sie sollten dies einfach tun:

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

gegeben eine Klasse wie:

class foo {
  private _bar:boolean = false;

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

dann wird der 'bar'-Getter für die private' _bar'-Eigenschaft aufgerufen.

TornadoAli
quelle
Wenn ich eine öffentliche Variable auf Klassenebene durch eine Eigenschaft ersetzen wollte, ist es dann ein direkter Drop-In-Ersatz, den ich einrichten kann, ohne mir darüber Sorgen zu machen? Mit anderen Worten, wenn ich einen Accessor und einen Setter einem Regressionstest unterziehe, kann ich dies als Erfolg betrachten? Oder gibt es Fälle, in denen es nicht genau so funktioniert wie ein Var und ich alle 100 Stellen testen muss, an denen dieser Var / Prop verwendet wird?
Adam Plocher
Ich habe mich gefragt, ob es eine Problemumgehung für die Verwendung von Unterstrichen gibt, um den Eigenschaftsnamen von den Getter- oder Setter-Methoden zu unterscheiden. In einem Kurs, den ich machte, sagten sie, Unterstriche seien nicht bevorzugt, gaben aber keine Alternative.
Cham
1
@cham Hier müssen Sie keine Unterstriche verwenden ... Sie können die private Variable notbar aufrufen, wenn Sie möchten.
Robert McKee
58

Hier ist ein Arbeitsbeispiel, das Sie in die richtige Richtung weisen sollte:

class Foo {
    _name;

    get Name() {
        return this._name;
    }

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

Getter und Setter in JavaScript sind nur normale Funktionen. Der Setter ist eine Funktion, die einen Parameter verwendet, dessen Wert der eingestellte Wert ist.

Brian Terlson
quelle
30
Um klar zu sein, müssen Eigentum, Getter und Setter nicht vorhanden sein static.
Drew Noakes
1
Die Variablenreferenzen sind jedoch immer noch statisch. Foo._namesollte ersetzt werden durchthis._name
Johannes
6

Du kannst das schreiben

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
quelle
2
Warum die Öffentlichkeit im Konstrukteur?
MuriloKunze
17
Ja, in diesem Code kann public im Konstruktor nicht enthalten sein. publicHier werden doppelte Mitglieder definiert.
Orad
2
Sie können es schreiben, aber es wird nicht kompiliert
Justin
3

TS bietet Getter und Setter, mit denen Objekteigenschaften mehr Kontrolle darüber haben, wie auf sie außerhalb des Objekts zugegriffen (Getter) oder sie aktualisiert (Setter) werden. Anstatt direkt auf die Eigenschaft zuzugreifen oder diese zu aktualisieren, wird eine Proxy-Funktion aufgerufen.

Beispiel:

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
quelle
1

Es ist dem Erstellen gängiger Methoden sehr ähnlich. Setzen Sie einfach das Schlüsselwort reserviert getoder setam Anfang.

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 diesem Fall können Sie die Rückgabe eingeben get getMethod1() {

    get getMethod1() {
        return this._name;
    }
Engel Engel
quelle
1

Ich denke, ich verstehe wahrscheinlich, warum es so verwirrend ist. In Ihrem Beispiel wollten wir Getter und Setter für _name. Dies erreichen wir jedoch, indem wir Getter und Setter für eine nicht verwandte Klassenvariable erstellen Name.

Bedenken Sie:

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

Der obige Code bewirkt Folgendes:

  1. getund seterstelle Getter und Setter für yourCarTiresCount( nicht fürtiresCount ).

Der Getter ist:

function() {
    return this.tiresCount ;
}

und der Setter ist:

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

Das heißt, jedes Mal, wenn wir es tun new Car().yourCarTiresCount, läuft Getter. Und für jeden new Car().yourCarTiresCount('7')Setter läuft.

  1. Indirekt erstellen Sie Getter, aber nicht den Setter für private Zwecke tireCount.
dasfdsa
quelle
0

Wenn Sie nach einer Möglichkeit suchen, get und set für ein Objekt (keine Klasse) zu verwenden, Proxy kann dies hilfreich sein: 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

Hinweis: Beachten Sie, dass dies eine neue API ist, die nicht unterstützt wird und für ältere Browser erforderlich ist

devi
quelle
-6

Wenn Sie mit TypeScript-Modulen arbeiten und versuchen, einen exportierten Getter hinzuzufügen, können Sie Folgendes tun:

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

Dann haben Sie in einer anderen Datei:

import * as dataStore from "./dataStore"
console.log(dataStore.myData); // "my data"
cjbarth
quelle
8
Das ist ein schrecklicher Rat. Insbesondere thismuss im obersten Bereich eines Moduls undefiniert sein. Sie könnten exportsstattdessen verwenden, aber Sie sollten es überhaupt nicht tun, da es praktisch garantiert Kompatibilitätsprobleme verursacht
Aluan Haddad