microsoft / TypeScript

TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
https://www.typescriptlang.org
Apache License 2.0
100.3k stars 12.39k forks source link

strictNullCheck False Posivitve when access propery on created object. #31202

Open Bene-Graham opened 5 years ago

Bene-Graham commented 5 years ago

TypeScript Version: 3.5.0-dev.20190501

Search Terms: strict false positive object

Code

import * as azure from "@azure/storage-blob";

interface ISaveBlobOptions {
    blobName: string;
    contentDisposition?: {
        fileName: string;
        type: "inline" | "attachment";
    };

    contentType: string;

    fileData: Buffer;
}

const saveBlobBase = async (input: ISaveBlobOptions): Promise<void> => {
    this.validateSaveBlobBase(input);

    await this.createStorage();

    const options: azure.IBlockBlobUploadOptions = {
        blobHTTPHeaders: {
            blobContentType: input.contentType
        }
    };

    if(input.contentDisposition) {
        // Getting Object is possibly 'undefined'.
        options.blobHTTPHeaders.blobContentDisposition = `${input.contentDisposition.type}; filename="${input.contentDisposition.fileName}"`;
    }

    if (input.fileData instanceof Buffer) {
        await this.saveBlobBuffer(input.blobName, input.fileData, options);
    } else if(this.isMulterFile(input.fileData)) {
        await this.saveBlobMulterFile(input.blobName, input.fileData, options);
    } else {
        throw new Error("Unknown type for param file");
    }
}

saveBlobBase({
    blobName: "myBlobName",
    contentDisposition: {
        fileName: "foo.bar",
        type: "inline"
    },
    contentType: "text/plain",
    fileData: Buffer.from("SOME TEXT")
});

tsconfig

{
    "compilerOptions": {
        "target": "es2017",
        "module": "commonjs",
        "sourceMap": true,
        "strictPropertyInitialization": true,
        "strictNullChecks": true
    }
}

Expected behavior:

since when the creating the options variable the property blobHTTPHeaders is also defined. I would expect that accessing properties off of blobHTTPHeaders should not throw a "Object is possibly 'undefined'."

Actual behavior:

Getting Object is possibly 'undefined'.

Playground Link:

Related Issues:

AlCalzone commented 5 years ago

According to https://docs.microsoft.com/de-de/javascript/api/@azure/storage-blob/iblockblobuploadoptions?view=azure-node-preview blobHTTPHeaders is an optional property on azure.IBlockBlobUploadOptions.

You told TypeScript that options is of type azure.IBlockBlobUploadOptions, which means that options.blobHTTPHeaders is optional. Whether you assign an object to it that has blobHTTPHeaders doesn't matter in that case. options.blobHTTPHeaders is not narrowed to "not undefined" in your code.

You can solve the problem by explicitly telling TypeScript how options looks like - in your case it is a { blobHTTPHeaders: BlobHTTPHeaders}.

AlCalzone commented 5 years ago

On 2nd thought, this seems to be a duplicate of https://github.com/Microsoft/TypeScript/issues/20219