Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why does TypeScript type narrowing not work in callback functions? [duplicate]

Tags:

typescript

The code below is what's causing the error

function upload(
    url: string,
    files: {
        file: File;
        fieldname: string;
    }[],
    options: {
        onProgress: Function;
        customData?: Record<string, any>;
        method?: string;
    } = {
        onProgress() {},
        method: "POST",
    }
) {
    options.customData &&
        Object.keys(options.customData).forEach(
            (fieldname) =>
                typeof options.customData[fieldname] !== "undefined" &&
                formData.append(fieldname, options.customData[fieldname])
        );
}

TS Playground

I'm getting this error; it's typescript specific:

'options.customData' is possibly 'undefined'. ts(18048)

options.customData && should narrow the type according to narrowing, but it doesn't work, if the access is inside a callback function.

Narrowing in the following code works:

function upload(
    url: string,
    files: {
        file: File;
        fieldname: string;
    }[],
    options: {
        onProgress: Function;
        customData?: Record<string, any>;
        method?: string;
    } = {
        onProgress() {},
        method: "POST",
    }
) {
    options.customData && options.customData["fieldname"];
}

TS Playground

like image 880
hoho hotstuff Avatar asked Oct 18 '25 15:10

hoho hotstuff


1 Answers

ts does not remember the narrowing in the forEach function call.

See TypeScript Type Narrowing Error with forEach

Short explanation is, that it does in general not know when the callback is executed, so the narrowing may not be valid any longer.

You can do

  const customData = options.customData
  customData
      && Object.keys(customData).forEach(
             (fieldname) => typeof customData[fieldname] !== 'undefined'
              && formData.append(fieldname, customData[fieldname])
         );
like image 72
mrtnlrsn Avatar answered Oct 20 '25 05:10

mrtnlrsn