Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

Constructors as object keys

I’m trying to construct a map of types and callbacks so I started with an structure like this:

type Instantiable<T = unknown> = new (...args: any[]) => T;
type SingleParamFn<TInput = unknown, TOuput = unknown> = (arg: TInput) => TOuput;

type TypesRecord<T> = { type: Instantiable<T>, callback: SingleParamFn<T> };
type TypesMap = TypesRecord[];   // This is the structure

An example of this:

const myMap: TypesMap = [{ type: Date, callback: (value) => 'this is a Date' }];

This seems works as expected but I realised it is a bit inefficient as you need to loop the array to find the type you want.

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

I started to play with having the types as object keys and it seems to work at least in Google Chrome:

class MyFancyObject {}
class MyOtherObject {}

const map = {
   [Date]: () => 'this is a date',
   [MyFancyObject]: () => 'this is a fancy object',
   [MyOtherObject]: () => 'this is another object'
};

console.log(map[Date]());           // 'this is a date'
console.log(map[MyFancyObject]());  // 'this is a fancy object'
console.log(map[MyOtherObject]());  // 'this is another object'

const obj = new MyFancyObject();
console.log(map[obj.constructor]());           // 'this is a fancy object'
console.log(map[(new Date()).constructor]());  // 'this is a date'

I’ve been checking some documentation and it seems like an object’s key can only be an string or a Symbol so I checked what constitutes a Symbol and it seems to be a bit vage as it is defined as a built-in object whose constructor returns a symbol primitive that’s guaranteed to be unique and an object’s constructor is (to the best of my knowledge), unique.

Given all of this, is using the constructors as object keys a reliable approach? If so, how can I define the typescript type for such object? If it isn’t, are there other options (like the Map object)?

>Solution :

Given all of this, is using the constructors as object keys a reliable approach?

No. As you said, an object’s keys can only be strings or Symbols. A Symbol is a primitive you get from a property on Symbol (for well-known, specification-defined Symbols) or by calling Symbol() or Symbol.for("..."). Constructor functions are not symbols, they’re functions.

Your map object’s keys are strings. When you use a computed property name like [MyFancyObject], if the value you provide is not a string or a Symbol (in your case, it’s a function), it’s converted to string implicitly as though you did String(MyFancyObject). You can see that here:

class MyFancyObject {}
class MyOtherObject {}

const map = {
   [Date]: () => 'this is a date',
   [MyFancyObject]: () => 'this is a fancy object',
   [MyOtherObject]: () => 'this is another object'
};

console.log(Object.keys(map));
console.log(map[MyFancyObject]());            // "this is a fancy object"
console.log(map["class MyFancyObject {}"]()); // also "this is a fancy object"

As you can see, the key you’re thinking of as MyFancyObject is actually the string "class MyFancyObject {}".

You can use constructor functions as keys in a Map, though:

class MyFancyObject {}
class MyOtherObject {}

const map = new Map([
   [Date, () => 'this is a date'],
   [MyFancyObject, () => 'this is a fancy object'],
   [MyOtherObject, () => 'this is another object'],
]);

console.log(map.get(MyFancyObject)());

In that, the keys really are the constructor functions, not strings derived from them.

Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading