#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
каким-то образом повторно использовать метод, чтобы это было точно так же, как написать его снова.