Skip to content

Optional properties coming from conditional spread lose "| undefined" #41418

Closed
@danvk

Description

@danvk

TypeScript Version: 4.2.0-dev.20201105

Search Terms:

  • spread optional

Expected behavior:

The start symbols should both have type number | undefined.

Actual behavior:

The one destructured from the conditional spread has somehow dropped the undefined.

Related Issues:

#39376

Code

I'd expect the two start variables in the following code to have the same type. But they don't, one is number, whereas the other is number | undefined:

declare let hasDates: boolean;

{
  const nameTitle = { name: 'Khufu', title: 'Pharaoh' };
  const pharaoh = {
    ...nameTitle,
    ...(hasDates && { start: -2589, end: -2566 }),
  };
  // type is const pharaoh: {
  //     start?: number;
  //     end?: number;
  //     name: string;
  //     title: string;
  // }, which is character-for-character identical to Reign, below.
  const { start } = pharaoh;
  // const start: number
}

interface Reign {
  start?: number;
  end?: number;
  name: string;
  title: string;
}
declare let reign: Reign;

{
  const { start } = reign;
  // const start: number | undefined
}
Output
"use strict";
{
    const nameTitle = { name: 'Khufu', title: 'Pharaoh' };
    const pharaoh = Object.assign(Object.assign({}, nameTitle), (hasDates && { start: -2589, end: -2566 }));
    // type is const pharaoh: {
    //     start?: number;
    //     end?: number;
    //     name: string;
    //     title: string;
    // }, which is character-for-character identical to Reign, below.
    const { start } = pharaoh;
    // const start: number
}
{
    const { start } = reign;
    // const start: number | undefined
}
Compiler Options
{
  "compilerOptions": {
    "noImplicitAny": true,
    "strictNullChecks": true,
    "strictFunctionTypes": true,
    "strictPropertyInitialization": true,
    "strictBindCallApply": true,
    "noImplicitThis": true,
    "noImplicitReturns": true,
    "alwaysStrict": true,
    "esModuleInterop": true,
    "declaration": true,
    "experimentalDecorators": true,
    "emitDecoratorMetadata": true,
    "moduleResolution": 2,
    "target": "ES2017",
    "jsx": "React",
    "module": "ESNext"
  }
}

Playground Link: Provided

Metadata

Metadata

Assignees

Labels

BugA bug in TypeScript

Type

No type

Projects

No projects

Relationships

None yet

Development

No branches or pull requests

Issue actions