[Tips] Expanding Native Type on Typescript

Background

Sometimes, We need to extend a native class(object) with inheritance. But some meta programmer has a different direction to solve it. They extend the native class by editing itself. It has beneficial because Not necessary to define a new extended class. There surely has some point you should take care of.

Let’s see on typescript

typescript provides these feature, it calls ‘Declaration merging

https://www.typescriptlang.org/docs/handbook/declaration-merging.html

This is example, The Array object extedns by adding the uniq method which eliminating duplicated item in a Array.

array.extensions.ts

export {}

declare global {
    interface Array<T> {
        uniq<T> (comparer: (value1: T, valu2: T) => boolean): T[];
        contains<T> (value: T): boolean;
    }
}

/* eslint no-extend-native: ["error", { "exceptions": ["Array"] }] */
Array.prototype.uniq = function<T> (comparer: (value1: T, valu2: T) => boolean): T[] {
    return this.filter((value1, index1, array1): boolean => {
        const index2 = array1.findIndex((value2): boolean => comparer(value1, value2))
        return (index1 === index2)
    })
}

To use this extension library, like this.

import './array.extensions'

['aaa','bbb','ccc','bbb','ccc']
.filter(elem => elem === 'ccc')
.uniq((v1,v2) => (v1 === v2))

objectの配列でも
[{ID:'aaa'}, {ID:'bbb'},{ID:'ccc'},{ID:'bbb'},{ID:'ccc'}]
.filter(elem => elem.ID === 'ccc')
.uniq((v1,v2) => (v1.ID === v2.ID))

Note

If you use eslint, You should turn off the no-extend-native rule. (like this)

/* eslint no-extend-native: ["error", { "exceptions": ["Array"] }] */

And, There is a risk of this feature that it spoil to native namespace. You should take care of spoiling namespace when you add (or extend) native object.