Est-il possible d'utiliser des getters / setters dans la définition d'interface?

93

Pour le moment, TypeScriptn'autorise pas l'utilisation de méthodes get / set (accesseurs) dans les interfaces. Par exemple:

interface I {
      get name():string;
}

class C implements I {
      get name():string {
          return null;
      } 
}

de plus, TypeScript n'autorise pas l'utilisation de l'expression de fonction Array dans les méthodes de classe: par exemple:

class C {
    private _name:string;

    get name():string => this._name;
}

Existe-t-il un autre moyen d'utiliser un getter et un setter sur une définition d'interface?

Ivan Popov
la source

Réponses:

125

Vous pouvez spécifier la propriété sur l'interface, mais vous ne pouvez pas imposer si les getters et les setters sont utilisés, comme ceci:

interface IExample {
    Name: string;
}

class Example implements IExample {
    private _name: string = "Bob";

    public get Name() {
        return this._name;
    }

    public set Name(value) {
        this._name = value;
    }
}

var example = new Example();
alert(example.Name);

Dans cet exemple, l'interface ne force pas la classe à utiliser des getters et des setters, j'aurais pu utiliser une propriété à la place (exemple ci-dessous) - mais l'interface est censée masquer ces détails d'implémentation de toute façon car c'est une promesse au code appelant sur ce qu'il peut appeler.

interface IExample {
    Name: string;
}

class Example implements IExample {
    // this satisfies the interface just the same
    public Name: string = "Bob";
}

var example = new Example();
alert(example.Name);

Enfin, =>les méthodes de classe ne sont pas autorisées - vous pouvez lancer une discussion sur Codeplex si vous pensez qu'il existe un cas d'utilisation brûlant pour celui-ci. Voici un exemple:

class Test {
    // Yes
    getName = () => 'Steve';

    // No
    getName() => 'Steve';

    // No
    get name() => 'Steve';
}
Fenton
la source
1
Vous pouvez l'utiliser =>pour définir des méthodes de classe comme celle-ci: name = (a: string) => this._name;mais dans le JS de sortie, elle sera définie dans la fonction de classe plutôt que d'étendre son objet prototype.
orad
44

Pour compléter les autres réponses, si votre désir est de définir un get valuesur une interface, vous pouvez utiliser readonly:

interface Foo {
  readonly value: number;
}

let foo: Foo = { value: 10 };

foo.value = 20; //error

class Bar implements Foo {
  get value() {
    return 10;
  }
}

mais pour autant que je sache, et comme d'autres l'ont mentionné, il n'y a actuellement aucun moyen de définir une propriété définie uniquement dans l'interface. Vous pouvez, cependant, déplacer la limitation vers une erreur d'exécution (utile pendant le cycle de développement uniquement):

interface Foo {
  /* Set Only! */
  value: number;
}

class Bar implements Foo {
  _value:number;
  set value(value: number) {
    this._value = value;
  }
  get value() {
    throw Error("Not Supported Exception");
  }
}

Pratique non recommandée ; mais une option.

Meirion Hughes
la source
2

Tout d'abord, Typescript ne prend en charge getet la setsyntaxe que pour cibler Ecmascript 5. Pour ce faire, vous devez appeler le compilateur avec

tsc --target ES5

Les interfaces ne prennent pas en charge les getters et les setters. Pour obtenir votre code à compiler, vous devrez le changer en

interface I { 
    getName():string;
}

class C implements I { 
    getName():string {
          return null;
    }   
}

Ce que dactylographié prend en charge, c'est une syntaxe spéciale pour les champs dans les constructeurs. Dans votre cas, vous pourriez avoir

interface I {
    getName():string;
}

class C implements I {
    constructor(public name: string) {
    }
    getName():string {
        return name;
    }
}

Remarquez que la classe Cne spécifie pas le champ name. Il est en fait déclaré en utilisant du sucre syntaxique public name: stringdans le constructeur.

Comme le souligne Sohnee, l'interface est en fait censée cacher tous les détails d'implémentation. Dans mon exemple, j'ai choisi l'interface pour exiger une méthode getter de style java. Cependant, vous pouvez également créer une propriété, puis laisser la classe décider comment implémenter l'interface.

Valentin
la source
1
Vous pouvez utiliser des mots get- setclés et dans TypeScript.
Fenton
Une note latérale sur la prise en charge d'ECMAScript 5 - Object.definePropertyest prise en charge dans IE8 +, FF4 +, Opera 12+, WebKit et Safari. Il y a aussi une cale EC5 sur github.com/kriskowal/es5-shim
Fenton
-1

En utilisant TypeScript 3.4:

interface IPart {
    getQuantity(): number;
}

class Part implements IPart {
    private quantity: number;
    constructor(quantity: number) {
        this.quantity = quantity;
    }
    public getQuantity = (): number => {
        return this.quantity;
    };
}

let part = new Part(42);

// When used in typescript, quantity is not accessible.
// However, when compiled to javascript it will log '42'.
console.log(part.quantity);

// Logs '42'.
console.log(part.getQuantity());

Voir l'exemple sur TypeScript Playground .

Jack
la source