Skip to content

Omitted property does not narrow discriminated union contextual type #41759

@andrewbranch

Description

@andrewbranch

TypeScript Version: 4.2.1

Search Terms: discriminated union optional property

Code

type DiscriminatorTrue = {
  disc: true;
  cb: (x: string) => void;
}

type DiscriminatorFalse = {
  disc?: false;
  cb: (x: number) => void;
}

type Props = DiscriminatorTrue | DiscriminatorFalse;

declare function f(options: DiscriminatorTrue | DiscriminatorFalse): any;

f({
  disc: true,
  cb: s => parseInt(s) // Inference works 👍 
});

f({
  disc: false,
  cb: n => n.toFixed() // Inference works 👍 
});

f({
  cb: n => n.toFixed() // Implicit any error 👎 
});

f({
  cb: (n: string) => parseInt(n) // But errors correctly with incorrect type annotation 👍 
});

Expected behavior:
No implicit any error on the third call site

Actual behavior:
Implicit any error on the callback parameter at the third call site

Playground Link

Related Issues: #31404 (comment) is this issue, but the OP there is different.

Notes:
This pattern sometimes appears in React component props, where convention is to make boolean properties optional and only pass them as true (usually with the shorthand <MyComponent boolProp />). I actually suggested using discriminated union props for React components in an old blog post, and noted this issue in a footnote, calling it a possible bug, but didn’t file it at the time because I had low confidence it wasn’t a duplicate or design limitation. It was later mentioned in #31404 (comment), but was probably ignored because it was assumed to be an instance of the OP’s issue, which was determined to be a design limitation. I dove into this again because someone tweeted at me asking about that footnote after reading the post.

Metadata

Metadata

Assignees

No one assigned

    Labels

    BugA bug in TypeScriptHas ReproThis issue has compiler-backed repros: https://aka.ms/ts-repros

    Type

    No type

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions