TypeScript is a supercharged version of JavaScript that provides static typing and powerful features like interfaces and type augmentation. One of the cool features of TypeScript is the ability to extend built-in prototypes (like String
, Array
, Number
) to add custom methods that can be used globally across your project.
In this blog post, we’ll build a TypeScript utility library that adds custom methods to native prototypes such as String
, Array
, and Number
. We’ll also learn how to extend global types using the declare
keyword, enabling us to use the extended methods throughout the project.
Why Extend Prototypes in TypeScript?
In JavaScript, native types like String
, Array
, and Number
come with a basic set of methods. However, you might want to add some additional functionality to these objects for your specific use case. For example:
- Converting strings to Title Case.
- Getting the sum of an array of numbers.
- Formatting a number as currency.
These enhancements are useful for improving code readability and maintainability, especially in large-scale applications.
Setting Up the TypeScript Project
First, let’s initialize a new TypeScript project and set up the environment:
-
Initialize the project
mkdir ts-utils cd ts-utils npm init -y
-
Install TypeScript
npm install typescript --save-dev
-
Create a
tsconfig.json
file
This configuration file tells TypeScript how to compile the project.{ "compilerOptions": { "target": "ES6", "module": "CommonJS", "strict": true, "outDir": "dist" } }
-
Create a
src
folder for our source codemkdir src
Extending Prototypes
Now, let’s extend the prototypes of String
, Array
, and Number
to add some useful utility methods.
1. Extending String
Prototype with toTitleCase()
We want to add a method called toTitleCase()
that converts a string into Title Case (e.g., “hello world” becomes “Hello World”).
// src/string-utils.ts
export {};
declare global {
interface String {
toTitleCase(): string;
}
}
// Adding method to String prototype
String.prototype.toTitleCase = function (): string {
return this.replace(/\b\w/g, (char) => char.toUpperCase());
};
In this code:
declare global
tells TypeScript that we’re modifying the globalString
type.- The
toTitleCase()
method is added to theString
prototype, which allows us to use this method on any string in our project.
2. Extending Array
Prototype with sum()
Next, let’s add a method called sum()
to the Array
prototype that calculates the sum of all numeric elements in an array.
// src/array-utils.ts
export {};
declare global {
interface Array<T> {
sum(): number;
}
}
// Adding method to Array prototype
Array.prototype.sum = function (): number {
return this.reduce((acc, num) => acc + (typeof num === "number" ? num : 0), 0);
};
Here:
- We declare the
sum()
method on theArray
prototype to add the capability of calculating the sum of numeric values in an array.
3. Extending Number
Prototype with toCurrency()
Finally, let’s create a method called toCurrency()
for the Number
prototype to format a number as a currency.
// src/number-utils.ts
export {};
declare global {
interface Number {
toCurrency(locale?: string, currency?: string): string;
}
}
// Adding method to Number prototype
Number.prototype.toCurrency = function (locale = "en-US", currency = "USD"): string {
return new Intl.NumberFormat(locale, { style: "currency", currency }).format(this);
};
In this snippet:
- The
toCurrency()
method formats a number as a currency string based on the providedlocale
andcurrency
options.
Making Sure TypeScript Knows About Our New Methods
We’ve successfully added new methods to the native prototypes, but we need TypeScript to recognize these additions. This is where the declare
keyword comes in.
By using declare global
, we tell TypeScript that we’re adding new methods to global types. This will make TypeScript aware of the new methods and help provide autocomplete and type checking in the rest of the project.
Creating the Main Index File
To ensure all these methods are available globally when we import the library, we need an index.ts
file that imports all the utility files.
// src/index.ts
import "./string-utils";
import "./array-utils";
import "./number-utils";
Testing the Utility Library
Now, let’s create a test file (test.ts
) to check if our utility functions are working as expected.
// test.ts
import "./src"; // Import utility methods
console.log("hello world".toTitleCase()); // "Hello World"
console.log([10, 20, 30].sum()); // 60
console.log((1234.56).toCurrency("en-US", "USD")); // "$1,234.56"
console.log((1234.56).toCurrency("en-IN", "INR")); // "₹1,234.56"
Building and Running the Project
Before running the test, let’s add a build script to package.json
.
"scripts": {
"build": "tsc"
}
Then, build and run the project:
-
Build the TypeScript code
npm run build
-
Run the test file
Usets-node
to run thetest.ts
file:npx ts-node test.ts
You should see the following output:
Hello World
60
$1,234.56
₹1,234.56
Publishing to NPM
Finally, let’s publish this as an NPM package:
-
Login to NPM
npm login
-
Update the
package.json
file with necessary details likename
,version
,main
, andtypes
:
{
"name": "ts-utils",
"version": "1.0.0",
"main": "dist/index.js",
"types": "dist/index.d.ts",
"scripts": {
"build": "tsc"
}
}
- Publish the package
npm run build npm publish
Using the Library in Another Project
Now, you can use your utility library in other TypeScript projects by simply installing it from NPM:
npm install ts-utils
And use it like this:
import "ts-utils";
console.log("typescript rocks".toTitleCase()); // "Typescript Rocks"
console.log([1, 2, 3, 4].sum()); // 10
console.log((99.99).toCurrency("en-GB", "GBP")); // "£99.99"
Conclusion
In this blog, we’ve learned how to extend built-in prototypes in TypeScript using the declare global
syntax. We created a small utility library that added helpful methods to the String
, Array
, and Number
types, and made sure TypeScript recognized these extensions for type checking and autocompletion.
This technique can be used to create reusable libraries that improve developer productivity and code readability. You can share or publish these libraries for use in other projects to make your life easier!
Happy coding! ✨