Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to properly extend Array prototype in Typescript 4.0.3?

I'm trying to extend the base Array interface with some custom methods. I looked around SO and typescript docs and finally put together the following code:

// In module Func.ts

declare global {
  type Array<T> = {
    intersperse(mkT: (ix: number) => T): T[];
  };
}

if (!('intersperse' in Array.prototype)) {
  Array.prototype.intersperse = function intersperse<T>(this: T[], mkT: (ix: number) => T): T[] {
    return this.reduce((acc: T[], d, ix) => [...acc, mkT(ix), d], []).slice(1);
  };
}

However, I'm getting the following errors:

// On type Array<T> = { ... }
Duplicate identifier 'Array'.ts(2300)

// On Array.prototype.intersperse = ...
Property 'intersperse' does not exist on type 'any[]'.ts(2339)

Also, whenever I try to use intersperse in some other file, I get the error

Property 'intersperse' does not exist on type 'Element[]'.ts(2339)

Which is to be expected, considering the declaration in Func.ts seemingly didn't work. From this I gather that the SO questions are outdated (or incomplete) and that something has changed since.

So, what's the best way to extend to get rid of these errors and extend the Array prototype? Before you say I'm not supposed to do so — yeah, I know all the risks, and I made an informed decision to do it anyway.

like image 652
Eugleo Avatar asked Jul 15 '26 02:07

Eugleo


1 Answers

Array is defined as an interface not a type. Interfaces in typescript are open ended and can be added to by multiple declarations. Types do not share the same feature.

export{}
declare global {
  interface Array<T>  {
    intersperse(mkT: (ix: number) => T): T[];
  }
}

if (!Array.prototype.intersperse) {
  Array.prototype.intersperse = function intersperse<T>(this: T[], mkT: (ix: number) => T): T[] {
    return this.reduce((acc: T[], d, ix) => [...acc, mkT(ix), d], []).slice(1);
  };
}

Playground Link

As T.J. Crowder mentioned you might consider using Object.defineProperty to ensure the property is not enumerable:

export {}
declare global {
  interface Array<T>  {
    intersperse(mkT: (ix: number) => T): T[];
  }
}

if (!Array.prototype.intersperse) {
  Object.defineProperty(Array.prototype, 'intersperse', {
    enumerable: false, 
    writable: false, 
    configurable: false, 
    value: function intersperse<T>(this: T[], mkT: (ix: number) => T): T[] {
      return this.reduce((acc: T[], d, ix) => [...acc, mkT(ix), d], []).slice(1);
    }
  });
}

Playground Link

like image 171
Titian Cernicova-Dragomir Avatar answered Jul 20 '26 07:07

Titian Cernicova-Dragomir



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!