Travis James
Travis James

Reputation: 1939

How can I instantiate an object based on a string value

I have a string that I want to use in an API factory to instantiate the correct object from a class. Here is the code:

import StoryApiService from './story'
import AssignmentApiService from './assignment'

let apiTypes = {
    story: null,
    assignment: null
}
let token

const getApi = (newToken, apiType = 'story') => {
    const isNewToken = newToken => newToken !== token
    const shouldCreateService = !apiTypes[apiType] || isNewToken

    if( shouldCreateService ) {
        const capitalizedServiceType = apiType.charAt(0).toUpperCase() + apiType.slice(1)

        // this line is what I need help with
        apiTypes[apiType] = new `${capitalizedServiceType}ApiService`(token)
    }
    return apiTypes[apiType]
}

So basically depending on the apiType argument that is passed in I want to instantiate a new object from the correct class. I want to avoid using if/else and switch statements if possible because I have a bunch of different apiServices that I will use and I think this way will be cleaner if its possible.

I know the line in the code above won't work as written but its pseudo code to show the effect I want to achieve.

Upvotes: 1

Views: 56

Answers (2)

Jordan Running
Jordan Running

Reputation: 106077

Rather than trying to instantiate a class from a string name (with some complex capitalization/concatenation logic), create an object that maps apiType names directly to their corresponding classes:

import StoryApiService from './story'
import AssignmentApiService from './assignment'

const services = {
    story: StoryApiService,
    assignment: AssignmentApiService,
}
const serviceInstances = {
    story: null,
    assignment: null,
}
let token

const getApi = (newToken, apiType = 'story') => {
    const isNewToken = newToken !== token
    const shouldCreateService = !serviceInstances[apiType] || isNewToken

    if (shouldCreateService) {
        token = newToken
        serviceInstances[apiType] = new services[apiType](token)
    }
    return serviceInstances[apiType]
}

Upvotes: 4

Do the same thing you're already doing with apiTypes[apiType]: access the object that holds that class/constructor function.

E.g. if it's a class that you defined in window scope:

const ObjectType = window[`${capitalizedServiceType}ApiService`];

And then remember to verify that's defined because you have no guarantee your string actually maps to a function or class:

if (ObjectType) {
  apiTypes[apiType] = new ObjectType(token);
} else {
  console.error(`Api service for "${capitalizedServiceType}" does not exist.`);
}

Upvotes: -1

Related Questions