Как повторно использовать методы класса в typescript

#typescript #oop #interface #prototype #composition

Вопрос:

Я знаю, что могу объявлять функции с помощью этого интерфейса с помощью TS:

 interface SayName {
  name: string;
  say(): string;
}

function say(this: SayName) {
  return this.name;
}
 

Затем я хотел использовать эту функцию в качестве методов класса для классов, реализующих интерфейс sayName. Я могу это сделать, например:

 export class Hello implements SayName {
  name = "hello";
  say = say;
}
 

И метод sayMethod будет работать просто отлично, но он не будет добавлен в цепочку прототипов, поэтому это будет не то же самое, что объявление метода.

Я мог бы сделать это вместо этого:

 export class Hello implements SayName {
  name = "hello";
}
export interface Hello extends SayName {}
Hello.prototype.say = say;
 

И это также работает, но мне не очень нравится это решение. У кого-нибудь есть идея получше?

Комментарии:

1. «но мне не очень нравится это решение» — почему оно вам не нравится?

2. Когда я это делаю, Typescript не проверяет, действительно ли я реализовал интерфейс. Это не даст мне ошибки, если я забуду добавить метод в прототип. И он думает, что метод находится на поверхности объекта , поэтому, если затем скопировать объект, например {...new Hello()} , typescript думает, что этот метод находится на копии (а это не так).

Ответ №1:

То, что вы сейчас делаете, является плохой практикой, потому что вы неправильно используете интерфейсы и this .

По сути, ваш код примерно переведен на этот JavaScript:

 function say(){
  return this.name;
}

function Hello(){}
Hello.name = 'hello';
Hello.say = say;
 

Смотрите, как prototype нигде не упоминается.

Чтобы что-то появилось в цепочке прототипов, оно должно быть объявлено как метод класса, геттер или сеттер.

Поэтому, чтобы сделать то, что вы хотите сделать, вы можете сделать что-то вроде этого:

 interface SayName {
  name: string;
  say(): string;
}

function say(this: SayName) {
  return this.name;
}

export class Hello implements SayName {
  name = "hello";
  get say(){
    return say;
  }
}
 

Это примерно переводится на:

 function say(){
  return this.name;
}

function Hello(){}
Hello.name = 'hello';
Object.defineProperty(Hello.prototype, 'say', {
  configurable: true,
  enumerable: false,
  get: function(){
    return say;
  }
});
 

Но опять же, то, чего вы достигли здесь, скорее всего, на самом деле не то, что вы ожидали, потому this.name function say() что этого не будет 'hello' . Для этого вам нужно будет использовать .bind, но это выходит за рамки этого вопроса.

Комментарии:

1. То, что я сделал сначала, было эквивалентно этому: function Hello(){ this.name="hello" this.say=say }

2. Геттер-это не то, что я хотел, он будет возвращать функцию каждый раз, когда она выполняется. Я просто хотел say каким-то образом повторно использовать метод, чтобы это было точно так же, как написать его снова.