Every TypeScript native, like Number, String, Array, Object, etc. contains an object known as a prototype. Every method that is on a prototype is inherited by every instance of that object. For example, we can provide every `Array instance with a unique method by extending its prototype:
Array.prototype.unique = function() {
return [...new Set(this)];
}
['1', '1', '2'].unique(); // ['1', '2']
new Array('1', '1', '2').unique(); // ['1', '2']
Note that if you can also ensure chaining capability by returning this:
['1', '1', '2'].unique().reverse(); // ['2', '1']
The most important and noteworthy criticism of extending prototypes has always been name collision where the eventual specification implementation is different than the framework implementation. While I understand that argument, you can combat it with prefixing function names. Adding super powers to a native prototype so that every instance has it is so useful that I'd never tell someone not to extend a prototype..