Last updated: Feb 27, 2024
Reading timeยท6 min

To extend String.prototype in TypeScript:
string.extensions.ts file.String interface and add the extension method.import './string.extensions' before using
it.Here is the content of string.extensions.ts:
// eslint-disable-next-line @typescript-eslint/no-unused-vars interface String { prefix(pre: string): string; } String.prototype.prefix = function (pre: string) { return pre + this; };
And here is how we import and use the new prefix method on the String
prototype:
import './string.extensions'; const str = 'world'; console.log(str.prefix('hello ')); // ๐๏ธ "hello world"
If I run my index.ts file, we can see that the prefix method gets
successfully invoked.

String, which will get merged with the original String interface.In the interface, we created a
prefix method, which adds leading characters to the original string and
returns the result.
this of the enclosing scope, which is not what you want.You could use this approach to extend String.prototype with any method. Here
is an example of a method that adds the passed-in strings together.
This is the code in the string.extensions.ts file:
interface String { add(...strings: string[]): string; } String.prototype.add = function (...strings) { return this + strings.join(''); };
And here is the index.ts file, which imports string.extensions and makes use
of the add method.
import './string.extensions'; const str = 'hello'; // ๐๏ธ "hello one two three" console.log(str.add(' one', ' two', ' three'));
Make sure to specify the correct path when importing the string.extensions.ts
module.
String.prototype, make sure your methods are not interfering with built-in method names unless intentionally overriding them (which can be confusing).Here is an example of how you would override the built-in toLowerCase()
method.
interface String { toLowerCase(): string; } String.prototype.toLowerCase = function () { return this.toUpperCase(); };
And here is the code in our index.ts file.
import './string.extensions'; const str = 'Hello World'; // ๐๏ธ "HELLO WORLD" console.log(str.toLowerCase());
Note that overriding built-in methods is confusing and should generally be avoided.
I've also written an article on how to extend Array.prototype in TS.
To extend Object.prototype in TypeScript:
object.extensions.ts file.Object interface and add the extension method.import './object.extensions' before using
it.Here is the content of object.extensions.ts:
// eslint-disable-next-line @typescript-eslint/no-unused-vars interface Object { // ๐๏ธ function log - no parameters, returns object log(): Record<string, unknown>; } // ๐๏ธ Don't use an arrow function Object.prototype.log = function () { console.log(this); return this as Record<string, unknown>; };
And here is how we import and use the new log method on the Object
prototype:
import './object.extensions'; const obj = { name: 'Tom', age: 30, }; obj.log();
If I run my index.ts file, we can see that the log method gets successfully
invoked.

Object, which will get merged with the original Object interface.In the interface, we created a log method, which returns an object with
string keys and unknown values.
The method simply logs the object and returns it.
this of the enclosing scope, which is not what you want.You could use this approach to extend Object.prototype with any method. Here
is an example that implements a merge method that merges 2 objects.
This is the code in the object.extensions.ts file:
interface Object { merge(obj: Record<string, unknown>): Record<string, unknown>; } Object.prototype.merge = function (obj: Record<string, unknown>) { return { ...this, ...obj }; };
And here is the index.ts file, which imports object.extensions and makes use
of the merge method.
import './object.extensions'; const obj = { name: 'Tom', age: 30, }; const merged = { country: 'Chile', city: 'Santiago' }.merge(obj); // ๐๏ธ {country: 'Chile', city: 'Santiago', name: 'Tom', age: 30} console.log(merged);
Make sure to specify the correct path when importing the object.extensions.ts
module.
Object.prototype, make sure your methods are not interfering with built-in method names unless intentionally overriding them (which can be confusing).Here is the original Object interface:
interface Object { constructor: Function; toString(): string; toLocaleString(): string; valueOf(): Object; hasOwnProperty(v: PropertyKey): boolean; isPrototypeOf(v: Object): boolean; propertyIsEnumerable(v: PropertyKey): boolean; }
For example, here is how you would
override the built-in toString() method.
interface Object { toString(): string; } Object.prototype.toString = function () { return 'hello'; };
And here is the code in our index.ts file.
import './object.extensions'; const obj = { name: 'Tom', age: 30, }; console.log(obj.toString()); // ๐๏ธ "hello"
Note that overriding built-in methods is confusing and should generally be avoided.
To extend Date.prototype in TypeScript:
date.extensions.ts file.Date interface and add the extension method.import './date.extensions' before using it.Here is the content of date.extensions.ts:
// eslint-disable-next-line @typescript-eslint/no-unused-vars interface Date { getTimestamp(): number; } Date.prototype.getTimestamp = function () { return this.getTime(); };
And here is how we import and use the new getTimestamp method on the
Date prototype:
import './date.extensions'; const date = new Date('2022-09-24'); // ๐๏ธ 1663977600000 console.log(date.getTimestamp());
If I run my index.ts file, we can see that the getTimestamp method gets
successfully invoked.

Date, which will get merged with the original Date interface.In the interface, we created a getTimestamp method, which returns the number
of milliseconds since the UNIX epoch.
this of the enclosing scope, which is not what you want.You could use this approach to extend Date.prototype with any method. Here is
an example of a method that formats the date as yyyy-mm-dd.
This is the code in the date.extensions.ts file:
interface Date { format(): string; } Date.prototype.format = function () { return formatDate(this); }; function padTo2Digits(num: number) { return num.toString().padStart(2, '0'); } function formatDate(date: Date) { return [ date.getFullYear(), padTo2Digits(date.getMonth() + 1), padTo2Digits(date.getDate()), ].join('-'); }
And here is the index.ts file, which imports date.extensions.ts and makes
use of the format method.
import './date.extensions'; const date = new Date('2022-09-24'); // ๐๏ธ "2022-09-24" console.log(date.format());
Make sure to specify the correct path when importing the date.extensions.ts
module.
Date.prototype, make sure your methods are not interfering with built-in method names unless intentionally overriding them (which can be confusing).Here is an example of how you would override the built-in getFullYear()
method.
interface Date { getFullYear(): number; } Date.prototype.getFullYear = function () { return 100; };
And here is the code in our index.ts file.
import './date.extensions'; const date = new Date('2022-09-24'); // ๐๏ธ 100 console.log(date.getFullYear());
Note that overriding built-in methods is confusing and should generally be avoided.
To extend Number.prototype in TypeScript:
number.extensions.ts file.Number interface and add the extension method.import './number.extensions' before using
it.Here is the content of number.extensions.ts:
// eslint-disable-next-line @typescript-eslint/no-unused-vars interface Number { sum(a: number): number; } Number.prototype.sum = function (a: number) { return Number(this) + a; };
And here is how we import and use the new sum method on the Number
prototype:
import './number.extensions'; const num = 100; console.log(num.sum(5000)); // ๐๏ธ 5100
If I run my index.ts file, we can see that the sum method gets successfully
invoked.

Number, which will get merged with the original Number interface.In the interface, we created a sum method, which adds 2 numbers and returns
the result.
this of the enclosing scope, which is not what you want.You could use this approach to extend Number.prototype with any method. Here
is an example of a method that adds leading zeros to a number.
This is the code in the number.extensions.ts file:
interface Number { addLeadingZeros(): string; } Number.prototype.addLeadingZeros = function () { return padToDigits(Number(this), 5); }; function padToDigits(num: number, totalLength: number) { return num.toString().padStart(totalLength, '0'); }
And here is the index.ts file, which imports number.extensions and makes use
of the addLeadingZeros method.
import './number.extensions'; const num = 100; // ๐๏ธ "00100" console.log(num.addLeadingZeros());
Make sure to specify the correct path when importing the number.extensions.ts
module.
Number.prototype, make sure your methods are not interfering with built-in method names unless intentionally overriding them (which can be confusing).This is what the original Number interface looks like:
interface Number { toString(radix?: number): string; toFixed(fractionDigits?: number): string; toExponential(fractionDigits?: number): string; toPrecision(precision?: number): string; valueOf(): number; }
Here is an example of how you would override the built-in toString() method.
interface Number { toString(): string; } Number.prototype.toString = function () { return 'hello world'; };
And here is the code in our index.ts file.
import './number.extensions'; const num = 100; // ๐๏ธ "hello world" console.log(num.toString());
Note that overriding built-in methods is confusing and should generally be avoided.
You can learn more about the related topics by checking out the following tutorials: