0

I've an object which contains global parameters. These parameters are lists (arrays or an object with keys) used by my components.

Some parameters are shared by 2 or more components. These parameters are stored in GLOBALS.global[parameter-name]. Other parameters are related to a component and are stored in GLOBALS.related[component-name][parameter-name].

const GLOBALS = {
    // Used by 2 or more components
    'global': {
        'colors': ['red', 'blue', 'green', 'yellow'],
        'icons': {
            'home': 'icon-home',
            'power': 'icon-power',
            'server': 'icon-server',
        }
    },
    // Related to components
    'related': {
        'component-1': {
            'direction': ['left', 'right', 'up', 'down'],
        },
        'component-2': {
            'direction': ['up', 'down'],
            'icon-set': {
                'arrow': { 'up': 'icon-arrow-up-1', 'down': 'icon-arrow-down-1' },
                'arrow-simple': { 'up': 'icon-arrow-up-2', 'down': 'icon-arrow-down-2' },
                'arrow-circle': { 'up': 'icon-arrow-up-3', 'down': 'icon-arrow-down-3' },
            }
        },
    }
};

For some user input checks I need to get those parameter lists and check if the user input is valid.

For example:

getGlobalParamList('color') // => returns ['red', 'blue', 'green', 'yellow']

getGlobalParamList('icons') // => returns ['home', 'power', 'server']

getGlobalParamList('isNotDefined') // => error message

I wrote this function:

const getGlobalParamList = (paramName: string): string[] => {
    // Check if key paramName exist in GLOBALS
    if (GLOBALS.global.hasOwnProperty(paramName)) {
        const paramList = GLOBALS.global[paramName];
        if (Array.isArray(paramList)) return paramList;
        if (typeof paramList === 'object') return Object.keys(paramList);
        console.error(`Global parameter name ${paramName} is neither an array nor an object.`);
        return [];
    }.
    console.error(`Undefined global parameter name ${paramName}.`);
    return [];
}

Then I get the typescript error: The element is implicitly of the type "any" because the expression of the type cannot be used for the index type.

I tryed to declare a type Global to the object but this did not work:

type Globals = {
    [key: string]: string | object | string[] | object[]
}

When I change the type to any it works, but then there is no more autocomplete for my GLOBALS object in Visual Studio Code.

type Globals = {
    [key: string]: any
}

Anyone a guess how to handle it? In the next step I want to create a function to access component-related parameters, for example getComponentParamList(componentName: string, paramName: string) :string[].

1 Answer 1

1

I would say it's a very "javascript way" of doing thing. There are ways to make your code work as is, but it can get unnecessarily complicated.

A simple answer to your issue would be to set noImplicitAny to false in your tsconfig file.

But then part of the safety that typescript gives you would be gone.

Another way (which I would consider better), a more typescript way, would just be to define the types you are using:

type Icons = {
    [name: string]: string
}
type IconsSet = {
    [name: string]: {
        [category: string]: string
    }
}
type GlobalParameters = {
    colors?: string[];
    icons?: Icons;
}
type ComponentParameters = {
    direction?: string[];
    iconsSet?: IconsSet;
}
type GlobalVariables = {
    global?: GlobalParameters;
    related?: ComponentParameters;
}

const GLOBALS: GlobalVariables = {
    //...
}

It might take you more time to write the code, but it's much better in the long run, and actually ends up being faster to maintain and update.

Sign up to request clarification or add additional context in comments.

2 Comments

Thank you! I've to read some stuff about the custom types but I did not find a nice docu with some examples yet. Is there any difference when saying [name: string]: string instead of [key: string]: string?
No difference really. « name » or « key » is just the name you give your key for readability. It won’t be used after declaring it.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.