Вот вроде-бы логичный вариант:
class MyDate extends Date {
constructor(dateTimeStr: string) {
super(dateTimeStr);
console.log(this, typeof(this));
this.setTime(this.getTime() + 1000);
}
}
Но оказывается, что, по всей видимости, от того, что super вызывает Date как функцию Date(), а не как класс new Date, то Date возвращает строку. Соответственно и this становится строкой.
Подскажите как нормально можно расширить Date.
Приведенный пример кода работает, если используется синтаксис ES6. Отличие от typescript в данном случае только в отсутствии типа параметра, передаваемого в конструктор.
Это возможно, так как класс в разделе спецификации о Date есть следующие строки:
The Date constructor is designed to be subclassable. It may be used as the value of an extends clause of a class definition. Subclass constructors that intend to inherit the specified Date behaviour must include a super call to the Date constructor to create and initialize the subclass instance with a [[DateValue]] internal slot.
Конструктор Date определен так, что возможно создавать подклассы. Он может использоваться как значение для extends в определении класса. Конструкторы подклассов, которые должны наследовать поведение Date должны включать вызов super, для создания и инициализации внутреннего слота [[DateValue]].
Убедиться, что все работает, можно на примере:
class MyDate extends Date {
constructor(dateTimeStr) {
super(dateTimeStr);
console.log(this, typeof(this));
this.setTime(this.getTime() + 1000);
}
}
var d = new MyDate("2017-07-26T00:00:00.000Z");
console.log(d.getDate()); // 26
Проблема заключается во внутреннем слоте [[DateValue]], к которому внутри обращаются все функции Date.
Поэтому следующий пример будет кидать исключение:
function MyDate(dateTimeStr) {
Date.call(this, dateTimeStr);
this.setTime(this.getTime() + 1000);
}
MyDate.prototype = Object.create(Date.prototype);
var d = new MyDate("2017-07-26T00:00:00.000Z");
Реализация, которая идет в typescript несколько сложнее
function MyDate(dateTimeStr) {
var _this = _super.call(this, dateTimeStr) || this;
console.log(_this, typeof (_this));
_this.setTime(_this.getTime() + 1000);
return _this;
}
В данном случае переписывается this, который будет возвращен из конструктора, и вызов _super.call(this, dateTimeStr) в данном случае эквивалентен вызову Date.call(this, dateTimeStr), что просто вернет строку.
Победить эту проблему может помочь ключ компиляции -target, если в нем указать ES6 и выше.
В случае ручной реализации, в похожем вопросе советуют создавать Date и менять ему прототип, например так:
function MyDate(dateTimeStr) {
var _this = new Date(dateTimeStr);
_this.setTime(_this.getTime() + 1000);
Object.setPrototypeOf(_this, MyDate.prototype);
return _this;
}
MyDate.prototype = Object.create(Date.prototype);
MyDate.prototype.foo = function(){
return `${this.getFullYear()}-${this.getMonth()+1}`;
}
var d = new MyDate("2017-07-26T00:00:00.000Z");
console.log(d.getDate()); // 26
console.log(d instanceof Date); // true
console.log(d instanceof MyDate); // true
console.log(d.foo()); //2017-7
Продвижение своими сайтами как стратегия роста и независимости