I am trying to create a class FooMap
that extends the default TypeScript Map
class by restricting the type of parameters it accepts. The reason I am extending the Map
class is because I want to write methods for that class that I will be accessing from different files.
The default Map class is Map<any,any>
, however the FooMap
class would be similar to a Map<number,Foo>
using the built-in number
type and user-defined Foo
type. The FooMap
would only accept these key/value pairs.
My attempt to to this was by passing a map in the constructor but I feel like there is a better way to do this.
// Say Foo class is defined as
export class Foo {
id: number;
name: string;
}
Now, the FooMap
class would be:
export class FooMap extends Map{
constructor(otherMap : Map<number,Foo>){
super(otherMap);
}
}
But this does not work since super()
only accepts an iterable, so there must be a better way to extend the Map
class.
I am trying to create a class FooMap
that extends the default TypeScript Map
class by restricting the type of parameters it accepts. The reason I am extending the Map
class is because I want to write methods for that class that I will be accessing from different files.
The default Map class is Map<any,any>
, however the FooMap
class would be similar to a Map<number,Foo>
using the built-in number
type and user-defined Foo
type. The FooMap
would only accept these key/value pairs.
My attempt to to this was by passing a map in the constructor but I feel like there is a better way to do this.
// Say Foo class is defined as
export class Foo {
id: number;
name: string;
}
Now, the FooMap
class would be:
export class FooMap extends Map{
constructor(otherMap : Map<number,Foo>){
super(otherMap);
}
}
But this does not work since super()
only accepts an iterable, so there must be a better way to extend the Map
class.
2 Answers
Reset to default 11You need to make your class extending a fully instantiated generic Map
as well:
export class FooMap extends Map<number, Foo> {
but to make it work you should target es6
(see https://github./Microsoft/TypeScript/issues/10853)
I am will extend zerkms' answer here with a succinct example:
tl;dr
- Create new class
FooMap
implementingMap<number, Foo>
- Add private inner
Map<number, Foo>
- Expose all the functionality of the
Map
class
3a. Use IDE to declare all the interface functions of Map
3b. For each function return the inner Map's same function call
class OptionalMap <K, V> implements Map<K, V> {
// Inner map
private _innerMap: Map<K, V>;
constructor(optionalFunctions: { fnName: string, fn: (value: V, ...args) => void }[]) {
this._innerMap = new Map<K, V>();
// My additional functionality to the standard Map. Note functionality is applied to this class not the inner Map
if(optionalFunctions) {
for (let optionalFunction of optionalFunctions) {
if(this[optionalFunction.fnName]) {
throw new Error(`Reserved function name: ${optionalFunction.fnName}`);
} else {
this[optionalFunction.fnName] = (key, ...args) => {
if(this.has(key)) {
optionalFunction.fn(this.get(key), ...args);
}
}
}
}
}
}
// Exposing all the inner map's inherit functions here in implementing the interface
clear(): void {
return this._innerMap.clear();
}
delete(key: K): boolean {
return this._innerMap.delete(key);
}
forEach(callbackfn: (value: V, key: K, map: Map<K, V>) => void, thisArg?: any): void {
return this._innerMap.forEach(callbackfn, thisArg);
}
get(key: K): V {
return this._innerMap.get(key);
}
has(key: K): boolean {
return this._innerMap.has(key);
}
set(key: K, value: V): this {
this._innerMap.set(key, value);
return this;
}
size: number;
entries(): IterableIterator<[K, V]> {
return this._innerMap.entries();
}
keys(): IterableIterator<K> {
return this._innerMap.keys();
}
values(): IterableIterator<V> {
return this._innerMap.values();
}
[Symbol.iterator](): IterableIterator<[K, V]> {
return this._innerMap.entries();
}
[Symbol.toStringTag]: string;
}
export default OptionalMap;