An example with classes

You can, of course, also use generics in your class definitions:

class NaiveMap<Key, Value> { 
    private _keys: Key[] = []; 
    private _values: Value[] = []; 
 
    constructor(){} 
 
    contains(key: Key): boolean { 
        const result = this._keys.indexOf(key); 
        return result !== -1; 
    } 
 
    put(key: Key, value: Value): void { 
        if(!this.contains(key)) { 
            this._keys.push(key); 
            this._values.push(value); 
        } 
    } 
 
    get(key: Key): Value | undefined { 
        if(this.contains(key)) { 
            return this._values[this._keys.indexOf(key)]; 
        } else{ 
            return undefined; 
        } 
    } 
} 
 
 
class Thing { 
    constructor(public name: string){} 
} 
 
const naiveMap = new NaiveMap<string, Thing>(); 
 
naiveMap.put("foo", new Thing("The thing")); 
console.log(naiveMap.contains("foo")); // true 
console.log(naiveMap.get("foo")); // Thing { name: 'The thing' } 

In this example, we have defined two generic parameters that we use to create generic arrays and define the input and output types of our functions.

Avoid implementing such general-purpose data structures yourself. Map and Set are actually supported natively in JavaScript and TypeScript: https://codecraft.tv/courses/angular/es6-typescript/mapset.

As you can see, thanks to generics, this very naive implementation of a Map data structure can be used with many different types and is therefore highly reusable. This also highlights the fact that, in a generic class, you may define generic members as we did previously (that is, the _keys and _values arrays).

As demonstrated earlier, you can define and use multiple generic parameters by separating them with a comma, as follows:

One more thing to note is that you can define default generic types for both interfaces and classes. This is especially useful for interfaces because it can allow you to omit generic types. The following is an example:

interface InterfaceWithDefaultGenericType<T=string> { 
    doSomething(arg: T): T 
} 
 
class ClassWithDefaultGenericType<T=string> { 
    constructor(public something: T) {} 
} 
 
interface InterfaceWithSpecializedGenericType<T = Person & {age: number}> { 
    doSomethingElse(arg: T): T 
} 
The previous example shows an even more advanced trick: defining custom types as the default generic type. It's good to know that this is possible, but it should certainly not be abused as it makes the code harder to understand and reason about.

Next, let's look at generic constraints.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.129.23.30