For a semi-educational side-project I'm working on, I've got a TypeScript interface
that exposes an id
variable on any object that implements it. In this app, it's reasonably common for there to be Array<>
s of these IIdable
objects.
Something I'm trying to do, since this application does not use a database, is implement an auto-incrementor to the service that keeps track of these list of IIdable
s. Naturally, I considered adding an extension the "JavaScript" way as below...
Array<MyProject.Models.IIdable>.prototype.getNextId = () => {
let biggestId: number = 0;
for (let current of this) {
if (current.id > biggestId)
biggestId = current.id;
}
return biggestId + 1;
};
...But Visual Studio Code throws a couple of errors, one of which is:
Cannot find name 'prototype'
I find this questionable, given that Array<T>
s are a JavaScript 'primitive', and given that everything is an object
in JavaScript (thus some of the problems that TypeScript was created to diminish or avoid outright.) However, I realize I know just enough of both JavaScript and TypeScript to be "dangerous", meaning I know enough things to permit myself to do something quite dumb.
If I were using C# - which TypeScript is not - I would write such an extension method something like this:
public static GetNextId(this List<IIdable> source)
{
// ...Read each IIdable's ID to figure out the next biggest to give.
}
...Unfortunately, I can't quite do that to my knowledge. I did some research on writing extension methods in TypeScript prior to posting this question. One such answer was to modify the host type's interface with the new method, which in this case I don't want to do. I only want to add an extension for cases when we're dealing with an Array<IIdable>
, and no others.
Thus, I must ask: In what way can I write an extension method on a generic type, for a specific type of thing, in TypeScript?
Assigning Generic Parameters By passing in the type with the <number> code, you are explicitly letting TypeScript know that you want the generic type parameter T of the identity function to be of type number . This will enforce the number type as the argument and the return value.
Generics are a way to tailor a class or method to a specific type. A generic method or class is designed to work for any type. This is most easily illustrated in the List<T> class, where it can be tailored to be a list of any type. This gives you the type-safety of knowing the list only contains that specific type.
The generic class Array
only has one prototype; you can't specify a type argument when accessing the prototype. However, you can override the this
type on the method. Here's how you would declare and then define the method. Note that you have to use a function
function, which is capable of receiving a this
parameter, and not an arrow function, which always uses the this
that was in scope where it was defined (which in this case is the global object).
interface Array<T> {
getNextId(this: MyProject.Models.IIdable[]): number;
}
// The `this` type for the function is taken from the declaration above.
Array.prototype.getNextId = function() {
let biggestId: number = 0;
for (let current of this) {
if (current.id > biggestId)
biggestId = current.id;
}
return biggestId + 1;
};
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With