I need the ability to easily sort collections and I've chosen to extend the Array primitive. I realize this is considered bad practice in most cases, but this will be used only internally (not a shared lib). No matter what approach I've tried I'm not getting a working result even though it works as expected in the playground.
I've tried adding the polyfill inline in /src/polyfills.ts
but that gives me a "TypeError: Attempted to assign to readonly property" in the console when I call the $sortBy
method...
declare global {
interface Array<T> {
$sortBy(sortKey:string): T[];
}
}
if (!Array.prototype['$sortBy']) {
Object.defineProperty(Array.prototype, '$sortBy', {
value: function(sortKey) {
return this.sort( function(a, b) { // TypeError here???
if (a[sortKey] < b[sortKey]) { return -1; }
if (a[sortKey] > b[sortKey]) { return 1; }
return 0;
});
}
})
}
I've also tried adding a plain javascript version via npm and importing but that gives me the same type error. What's the secret???
/node_modules/my-polyfills/sortBy.js
if (!Array.prototype.$sortBy) {
Object.defineProperties(Array.prototype, {
'$sortBy': {
value: function (sortKey) {
return this.sort(function (a, b) {
if (a[sortKey] < b[sortKey]) {
return -1;
}
if (a[sortKey] > b[sortKey]) {
return 1;
}
return 0;
});
}
}
});
}
.angular-cli.json
{
"$schema": "./node_modules/@angular/cli/lib/config/schema.json",
"project": { ... },
"apps": [
{
...,
"scripts": [
"../node_modules/my-polyfills/sortBy.js",
"../node_modules/moment/moment.js"
],
...
}
],
...
}
I have an generated app on angular cli 1.0.0. While I think your issue has nothing to do with the version, I have taken your code below and appended it to src/polyfills.ts
it works as expected:
declare global {
interface Array<T> {
$sortBy(sortKey:string): T[];
}
}
if (!Array.prototype['$sortBy']) {
Object.defineProperty(Array.prototype, '$sortBy', {
value: function(sortKey) {
return this.sort( function(a, b) { // TypeError here???
if (a[sortKey] < b[sortKey]) { return -1; }
if (a[sortKey] > b[sortKey]) { return 1; }
return 0;
});
}
})
}
in one of my components I added:
var a = [1,2,3];
var b = a.$sortBy('');
console.log(b)
I did not see the error in the console and array a
was printed just fine.
I think the issue you are having is because you have the code above in your src/polyfills.ts
AND you have included the same polyfill in /node_modules/my-polyfills/sortBy.js
and added that to scripts
section of your .angular-cli
You should add either or, not both. I recommend the former, but in it's own file and not appended to polyfills.ts
this error TypeError: Attempted to assign to readonly property
happens when you try to assign a non-writable property to something else. By using Object.defineProperty you are making $sortBy
non-writable. You defined Arrays.prototype.$sortBy THEN you try to modify that $sortBy by assigning it to a new function, hence you get the error.