javascript - ES6 Sınıfları ile Yerleşik Diziyi Genişletme - Metot bir fonksiyon değil hatası
Yerleşik dizi sınıfını genişletmeye ve yerel dizi sınıfına dayalı özel koleksiyonlar oluşturmaya çalışıyorum.
Özel isimle koleksiyon oluşturabiliyorum, bu iyi çalışıyor, ama özel metodlarımı kullanamıyorum. findAnimal metodunu kullanırsam bana method is not a function hatası veriyor. Koleksiyonu loglarsam ve prototipleri incelersem özel metodlarımı göremiyorum.
Kodu es5'e transpile ettiğimi fark ettim ve eğer etmezsem, düzgün çalışıyor; sorun ts derleyicisinin es5'e düşürülmüş kodunda ortaya çıkıyor.
Eğer kodu es5'e düşürmek için babel kullanırsak, dönüştürülmüş kod iyi çalışıyor. Ya ts derleyici kodu dönüştürürken bir şeyi kaçırıyor ya da ben bazı önemli bir yapılandırmayı kaçırıyorum.
interface Animal {
name: string;
weight: number
}
class AnimalCollection extends Array <Animal> {
constructor(name, ...items) {
super(...items);
Object.defineProperty(this, 'name', {
enumerable: false,
writable: false,
value: name
})
}
findAnimal(name): Animal {
return this.find(a => a.name === name) || null;
}
}
const animalsArray = [
{name: 'TD-23', weight: 60},
{name: 'TD-25', weight: 50},
{name: 'TXD-26', weight: 120},
{name: 'TYD-26', weight: 40}
];
const animals = new AnimalCollection('Deers', ...animalsArray)
console.log(animals.findAnimal('TD-23'));
// Uncaught TypeError: animals.findAnimal is not a function
ES5'e Düşürüldü
var __extends = (this && this.__extends) || (function () {
var extendStatics = function (d, b) {
extendStatics = Object.setPrototypeOf ||
({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
return extendStatics(d, b);
};
return function (d, b) {
extendStatics(d, b);
function __() { this.constructor = d; }
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
})();
var __spreadArrays = (this && this.__spreadArrays) || function () {
for (var s = 0, i = 0, il = arguments.length; i < il; i++) s += arguments[i].length;
for (var r = Array(s), k = 0, i = 0; i < il; i++)
for (var a = arguments[i], j = 0, jl = a.length; j < jl; j++, k++)
r[k] = a[j];
return r;
};
var AnimalCollection = /** @class */ (function (_super) {
__extends(AnimalCollection, _super);
function AnimalCollection(name) {
var items = [];
for (var _i = 1; _i < arguments.length; _i++) {
items[_i - 1] = arguments[_i];
}
var _this = _super.apply(this, items) || this;
Object.defineProperty(_this, 'name', {
enumerable: false,
writable: false,
value: name
});
return _this;
}
AnimalCollection.prototype.findAnimal = function (name) {
return this.find(function (a) { return a.name === name; }) || null;
};
return AnimalCollection;
}(Array));
var animalsArray = [
{ name: 'TD-23', weight: 60 },
{ name: 'TD-25', weight: 50 },
{ name: 'TXD-26', weight: 120 },
{ name: 'TYD-26', weight: 40 }
];
var animals = new (AnimalCollection.bind.apply(AnimalCollection, __spreadArrays([void 0, 'Deers'], animalsArray)))();
console.log(animals.findAnimal('TD-23'));
Cevap #1
GÜNCELLENMİŞ CEVAP
Değiştirilmiş sorunuza cevap vermek gerekirse, TypeScript size Array, Error gibi yerleşikleri genişletme izni vermez. Sebebi burada yazılmıştır.
ES2015'te, bir nesne döndüren yapıcılar, super(...) çağrılarını yapan herhangi bir çağırıcı için bu değerinin yerine geçer. Oluşturulmuş yapıcı kodunun super(...) çağrısının olası herhangi bir dönüş değerini yakalaması ve bunu bu değeri ile değiştirmesi gerekir.
Sonuç olarak, Error, Array ve diğerlerinin alt sınıflandırılması artık beklendiği gibi çalışmayabilir. Bunun nedeni, Error, Array ve benzerlerinin yapıcı fonksiyonlarının prototip zincirini ayarlamak için ECMAScript 6's new.target'ı kullanmasıdır; ancak ECMAScript 5'te bir yapıcıyı çağırırken new.target için bir değer sağlamak mümkün değildir. Diğer eski seviye derleyiciler de varsayılan olarak genellikle aynı sınırlamaya sahiptir.
Yani, eğer ES5 ortamında yerleşik Array öğesini genişletmek zorundaysanız, kodunuzu derlemek için Babel'i deneyebilirsiniz. Ancak, burada belirtildiği gibi bunun sınırlamaları olduğunu unutmayın.
Date, Array, DOM gibi yerleşik sınıflar, ES5'teki sınırlamalar nedeniyle (transform-classes eklentisi için) düzgün bir şekilde alt sınıflandırılamaz. Object.setPrototypeOf ve Reflect.construct'a dayalı babel-plugin-transform-builtin-extend kullanmayı deneyebilirsiniz, ancak bunun da bazı sınırlamaları vardır.
ESKİ CEVAP
Kodun kendisi tamamen doğru ve tarayıcıda da sorunsuz çalışıyor, bence aldığınız hata TypeScript derleyicisinden kaynaklanıyor.
Kaynak kod için
interface Animal {
name: string;
weight: number
}
class AnimalCollection extends Array <Animal> {
constructor(name: string, ...items: Animal[]) {
super(...items);
Object.defineProperty(this, 'name', {
enumerable: false,
writable: false,
value: name
})
}
findAnimal(name:string): Animal | null {
return this.find(a => a.name === name) || null;
}
}
const animalsArray = [
{name: 'TD-23', weight: 60},
{name: 'TD-25', weight: 50},
{name: 'TXD-26', weight: 120},
{name: 'TYD-26', weight: 40}
];
const animals = new AnimalCollection('Deers', ...animalsArray)
console.log(animals.findAnimal('TD-23'));
Eğer derleyici hedef seçeneği ES5 olarak ayarlanmışsa, o zaman uygulamayı bozan kod üretir. Ürettiği kod şudur
"use strict";
var __extends = (this && this.__extends) || (function () {
var extendStatics = function (d, b) {
extendStatics = Object.setPrototypeOf ||
({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
return extendStatics(d, b);
};
return function (d, b) {
extendStatics(d, b);
function __() { this.constructor = d; }
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
})();
var __spreadArrays = (this && this.__spreadArrays) || function () {
for (var s = 0, i = 0, il = arguments.length; i < il; i++) s += arguments[i].length;
for (var r = Array(s), k = 0, i = 0; i < il; i++)
for (var a = arguments[i], j = 0, jl = a.length; j < jl; j++, k++)
r[k] = a[j];
return r;
};
var AnimalCollection = /** @class */ (function (_super) {
__extends(AnimalCollection, _super);
function AnimalCollection(name) {
var items = [];
for (var _i = 1; _i < arguments.length; _i++) {
items[_i - 1] = arguments[_i];
}
var _this = _super.apply(this, items) || this;
Object.defineProperty(_this, 'name', {
enumerable: false,
writable: false,
value: name
});
return _this;
}
AnimalCollection.prototype.findAnimal = function (name) {
return this.find(function (a) { return a.name === name; }) || null;
};
return AnimalCollection;
}(Array));
var animalsArray = [
{ name: 'TD-23', weight: 60 },
{ name: 'TD-25', weight: 50 },
{ name: 'TXD-26', weight: 120 },
{ name: 'TYD-26', weight: 40 }
];
var animals = new (AnimalCollection.bind.apply(AnimalCollection, __spreadArrays([void 0, 'Deers'], animalsArray)))();
console.log(animals.findAnimal('TD-23'));
Ancak, eğer tsconfig.json içindeki target değerini ES2015 veya daha yüksek bir değere ayarlarsak, o zaman ürettiği kod şudur
"use strict";
class AnimalCollection extends Array {
constructor(name, ...items) {
super(...items);
Object.defineProperty(this, 'name', {
enumerable: false,
writable: false,
value: name
});
}
findAnimal(name) {
return this.find(a => a.name === name) || null;
}
}
const animalsArray = [
{ name: 'TD-23', weight: 60 },
{ name: 'TD-25', weight: 50 },
{ name: 'TXD-26', weight: 120 },
{ name: 'TYD-26', weight: 40 }
];
const animals = new AnimalCollection('Deers', ...animalsArray);
console.log(animals.findAnimal('TD-23'));
Bu elbette işe yarıyor. Yani bence ES5 veya daha düşük sürümler için TypeScript derleyicisinde uygulamayı bozan bir sorun var. Derleme için Babel kullanmayı denedim ve ES5 için işe yarıyor.
Cevap #2
Eksik olan bazı any'leri fark edebiliyorum, benim için çalışan kod şu:
interface Animal {
name: string;
weight: number
}
class AnimalCollection extends Array <Animal> {
constructor(name: string, ...items : Array <Animal>) { // <-- missing types
super(...items);
Object.defineProperty(this, 'name', {
enumerable: false,
writable: false,
value: name
})
}
findAnimal(name : any): Animal|null { // <-- missing null
return this.find(a => a.name === name) || null;
}
}
const animalsArray = [
{name: 'TD-23', weight: 60},
{name: 'TD-25', weight: 50},
{name: 'TXD-26', weight: 120},
{name: 'TYD-26', weight: 40}
];
const animals = new AnimalCollection('Deers', ...animalsArray)
console.log(animals.findAnimal('TD-23'));
Ancak bu kod aşağıdaki JS'i üretir:
"use strict";
class AnimalCollection extends Array {
constructor(name, ...items) {
super(...items);
Object.defineProperty(this, 'name', {
enumerable: false,
writable: false,
value: name
});
}
findAnimal(name) {
return this.find(a => a.name === name) || null;
}
}
const animalsArray = [
{ name: 'TD-23', weight: 60 },
{ name: 'TD-25', weight: 50 },
{ name: 'TXD-26', weight: 120 },
{ name: 'TYD-26', weight: 40 }
];
const animals = new AnimalCollection('Deers', ...animalsArray);
console.log(animals.findAnimal('TD-23'));
Hiçbir hata üretmeyen
