Home > Enterprise >  TypeScript complains about undefined even when default param is initialized
TypeScript complains about undefined even when default param is initialized

Time:10-27

The problem is TypeScript thinks the value I provide for the UiConfigContext.Provider may be undefined. Probably because of the ? config optional param however, I do provide the default { [Permission.Read]: true}. I don't understand why it still thinks it could ever be undefined. I want this function's parameter to be optional so anything like that would work:

renderTestComponent();
renderTestComponent({ config: { [Permission.Read]: true });
renderTestComponent({ enterDetails: true });
renderTestComponent({ config: { [Permission.Read]: true }, enterDetails: true );

Here's my code (replicated error in TypeScript playground)

import React, { createContext } from 'react';

enum Permission {
    Read = 'Read',
    Write = 'Write',
}

type Configuration = Partial<Record<Permission, boolean>>;

export const UiConfigContext = createContext<Configuration | null>(null);

function renderTestComponent(args: {
    config?: Configuration;
    enterDetails?: boolean;
} = {
    config: { [Permission.Read]: true},
    enterDetails: false
}) {
    <UiConfigContext.Provider value={args.config}>
        Test
    </UiConfigContext.Provider>
}

CodePudding user response:

By adding a question mark to the config?: type definition, TypeScript assumes that the property might end up undefined. If you know for sure, that it will never be undefined, remove the optional flag. Otherwise check if it is defined

...{args.config ? <UiConfigContext.Provider value={args.config}>
        Test
</UiConfigContext.Provider>: null}...

CodePudding user response:

There are 2 problems: Firstly, the type with ? tells Typescript that it could be undefined. Secondly, with your current default parameters it actually could be undefined at runtime, depending on how you call it.

The first problem can be solved, by removing the ?.

function renderTestComponent(args: {
    config: Configuration; // <-- removed the ?
    enterDetails: boolean; // <-- removed the ?
} = {
    config: { [Permission.Read]: true},
    enterDetails: false
}) {
    // ...
}

However, now it doesn't accept to call it with a partial object, e.g. renderTestComponent({}); or renderTestComponent({ enterDetails: true });. In such a case it doesn't assign the default parameter, because you provided it a value ({}). Because config is undefined, typescript complains now.

For this second problem I'd suggest to use default parameters and destructuring as follows. Here we assign the default value in each property, instead of the whole object at once:

function renderTestComponent({
    config = { [Permission.Read]: true },
    enterDetails = false
  } = {}) {
    console.log(config)
} 

renderTestComponent();
renderTestComponent({ config: { [Permission.Read]: true }});
renderTestComponent({ enterDetails: true });
renderTestComponent({ config: { [Permission.Read]: true }, enterDetails: true });

Here is a working example: https://tsplay.dev/m0L6Gm

  • Related