You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Extending Core Classes in C#, JavaScript & TypeScript
This article will teach your how to extend the core array class with custom methods in various languages. To apply this we'll make use of:
Extension Methods (C#)
Prototypes and Classes (JavaScript)
Types and Prototypes and Classes (TypeScript)
We're going to make a new method isEmpty that is going to check if the array, list or collection is empty.
So when a consumer calls this method it will return true or false.
collection.isEmpty()// T / F
Doing this is super simple and we'll see how it looks like in different languages.
Extending Core Class in JavaScript using Prototypes
To extend Core Class in JavaScript we make use of the Prototype Inheritance
Te prototype is like a tree where all properties and methods on the certain class/object exist.
constmyArr: string[]=[];
To verify that this array is empty we can make use of length property
if(myArr.length===0)// array is empty
To abstract this logic in it's own method we'll use the Prototype on the Array class
It's important to use the function expression here as opposed to arrow function because we need to make use of this keyword
this keyword referrs to an array that will use the isEmpty method
Use cases:
1)
if(myArr.isEmpty())// T / F
2)
constmyArr=[]myArr.isEmpty()// True
3)
constmyArr=[1,2,3]myArr.isEmpty()// False
However, here we encounter an issue as this cannot be applied on collections like Set or Map as those classes do not use length property.
They use size property.
So we'll need to come up with solution that can be applied to all cases (arrays, maps and sets)
Unified Solution for all Collections
Since arrays, sets and maps are all inheriting from Object class in JavaScript, the easiest way to apply
unified solution for all three is to extend the Object class and write logic for each case.
Here we also need to check if consumer is array or map/set or other type.
Object.prototype.isEmpty=function(){if(thisinstanceofArray){returnthis.length===0;// in case object is array use length property}if(thisinstanceofMap){returnthis.size===0;// in case object is map use size property}if(thisinstanceofSet){returnthis.size===0;// in case object is set use size property}return;// in neither case return undefined};
The final return is super important as there are other classes in JS that inherit from Object base class. Extending the Object class
with isEmpty method means that every object has that property and we do not want that. There is no point of getting the length
of a Date class or similar instances.
Extending Core Class in TypeScript using Prototypes
To use Prototypes in TypeScript we need to do some additional work.
For starter if we do this in TypeScript the compiler will complain that isEmpty method does not exist on type of array.
Array.prototype.isEmpty=function(){returnthis.length===0;};// Property 'isEmpty' does not exist on type 'any[]'.ts(2339)
To solve this issue we need to create a .d.ts file where we'll specify rules for types we'll use.
Basically we'll create isEmpty method for each type.
// index.d.ts fileexport{};declare global {interfaceArray<T>{isEmpty(): boolean;}}declare global {interfaceSet<T>{isEmpty(): boolean;}}declare global {interfaceMap<K,V>{isEmpty(): boolean;}}
Then we just create index.ts file and make use of the prototype.
Note we do not import d.ts file.
Alternative Solution for extending Core Classes JS/TS
So far we've been using inheritance by Prototype, but both JavaScript and
TypeScrpt also support class inheritance (that uses prototypes under the hood).
For example we can create a custom array class called ExtendedArray that has all properties and methods of an Array class,
with our additional properties.
Looking at the examples above you may noticed that three different collections use different ways to insert data:
push in Array
set in Map
add in Set
Using the same logic we added above we could create a unified method (insert) that would work for all three.
classExtendedMap<K,V>extendsMap<K,V>{constructor(){super();}isEmpty(){returnthis.size===0;}insert(key: K,value: V){// where K,V are to types pased to insert (e.g. string, string)this.set(key,value)}}constmyMap=newExtendedMap<string,string>();// where K,V are stringsconsole.log(myMap.isEmpty());// TruemyMap.insert('Hello','World')console.log(myMap.isEmpty());// False//classExtendedSet<T>extendsSet<T>{constructor(){super();}isEmpty(){returnthis.size===0;}insert(value: T){this.add(value)}}constmySet=newExtendedSet<string>();// where T is stringconsole.log(mySet.isEmpty());// TruemySet.insert('Hello')console.log(mySet.isEmpty());// False//classExtendedArray<T>extendsArray<T>{constructor(){super();}isEmpty(){returnthis.length===0;}insert(value: T){this.push(value);}}constmyArr=newExtendedArray<string>();// where T is stringconsole.log(myArr.isEmpty());myArr.insert('Hello')console.log(myArr.isEmpty());
Extending the prototype
There first thing we need to do is update the index.d.ts file.
export{};declare global {interfaceArray<T>{isEmpty(): boolean;insert(value: T): void}}declare global {interfaceSet<T>{isEmpty(): boolean;insert(value: T): void}}declare global {interfaceMap<K,V>{isEmpty(): boolean;insert(key: K,value: V): void}}
To abstract this method like we did with Prototypes in JavaScript, we'll make use of the Extension Methods.
This is how we make IsEmpty method in C# for the arrays.
publicstaticclassUtils{publicstaticboolIsEmpty(thisArraycollection)// this referrs to the consumer array{return collection.Length ==0;}}
Let's use it:
using System;publicclassProgram{publicstaticvoidMain(){varmyArr=newstring[0];
Console.WriteLine(myArr.IsEmpty());// True}}
Lists
In case of lists, we use the Count method to verify the size.
using System;using System.Collections.Generic;publicclassProgram{publicstaticvoidMain(){varmyList=newList<string>();
Console.WriteLine(myList.Count ==0);// True}}
To turn this into an Extension Method it would look like this:
publicstaticclassUtils{publicstaticboolIsEmpty<T>(thisList<T>collection)// this referrs to the list that will call this method{return collection.Count ==0;}}
Let's use it:
using System;using System.Collections.Generic;publicclassProgram{publicstaticvoidMain(){varmyList=newList<string>();
Console.WriteLine(myList.IsEmpty());// True}}
Once again we want to create a unified solution that would work for all collections.
On the positive side of things, C# has the same core class for all collections called Enumerable and the interface IEnumerable.
With this in mind we can use IEnumerable for collections instead of been specific if it is an array, list, dictionary, etc.
Let's update our Utils class.
publicstaticclassUtils{publicstaticboolIsEmpty<T>(thisIEnumerable<T>collection){returncollection!=null&&!collection.Any();// Any() method is available on all IEnumerables}
The solution above will work for both lists and arrays as seen below.
To be able to pass parameters to collection we simply need to add them to methods we're creating.
publicstaticclassUtils{publicstaticboolIsGreaterThan<T>(thisList<T>collection,intsize)// size is the parameter that we pass{returncollection!=null&& collection.Count >size;}}
Consumer Class
using System;using System.Collections.Generic;publicclass Program
{publicstaticvoid Main(){varmyList=newList<string>();
Console.WriteLine(myList.IsGreaterThan(100));// False