You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Omitted property does not narrow discriminated union contextual type #41759
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.
In this case, I think this'd be fixable by adjusting discriminateContextualTypeByObjectMembers and discriminateContextualTypeByJSXAttributes to include undefined'able discriminant props which don't appear in the node's properties. (They both currently filter the props which do exist on the input object down to the discriminant ones right now, so the possibly undefined discriminants from the contextual type would need to be appended to those)
// Solution is to specify all props from the non optional `enabled` as optional undefined fieldstypeB3=|{enabled?: false;foo?: undefined}|{enabled: true;foo: string;};// err as expected ✅exportconsta5: Props&B3={mode: true,nodes: ",",};
but it's not very nice. (I came across this when I was trying to use discriminated unions for react prop types)
👋 Hi, I'm the Repro bot. I can help narrow down and track compiler bugs across releases! This comment reflects the current state of the repro in the issue body running against the nightly TypeScript.
Argument of type '{ cb: (n: string) => number; }' is not assignable to parameter of type 'DiscriminatorTrue | DiscriminatorFalse'.
Type '{ cb: (n: string) => number; }' is not assignable to type 'DiscriminatorFalse'.
Types of property 'cb' are incompatible.
Type '(n: string) => number' is not assignable to type '(x: number) => void'.
Types of parameters 'n' and 'x' are incompatible.
Type 'number' is not assignable to type 'string'.
Historical Information
Version
Reproduction Outputs
4.3.2, 4.4.2, 4.5.2, 4.6.2
❌ Failed:
-
Argument of type '{ cb: (n: string) => number; }' is not assignable to parameter of type 'DiscriminatorTrue | DiscriminatorFalse'.
Type '{ cb: (n: string) => number; }' is not assignable to type 'DiscriminatorFalse'.
Types of property 'cb' are incompatible.
Type '(n: string) => number' is not assignable to type '(x: number) => void'.
Types of parameters 'n' and 'x' are incompatible.
Type 'number' is not assignable to type 'string'.
4.2.2
❌ Failed:
-
Parameter 'n' implicitly has an 'any' type.
Argument of type '{ cb: (n: string) => number; }' is not assignable to parameter of type 'DiscriminatorTrue | DiscriminatorFalse'.
Type '{ cb: (n: string) => number; }' is not assignable to type 'DiscriminatorFalse'.
Types of property 'cb' are incompatible.
Type '(n: string) => number' is not assignable to type '(x: number) => void'.
Types of parameters 'n' and 'x' are incompatible.
Type 'number' is not assignable to type 'string'.
Hm, so it seems like #43633 originally fixed this but caused a crash and was reverted, and then #43937 promptly fixed it again and caused a performance regression that has not been reverted or fixed 😕
Activity
weswigham commentedon Dec 1, 2020
In this case, I think this'd be fixable by adjusting
discriminateContextualTypeByObjectMembersanddiscriminateContextualTypeByJSXAttributesto includeundefined'able discriminant props which don't appear in thenode's properties. (They both currently filter the props which do exist on the input object down to the discriminant ones right now, so the possiblyundefineddiscriminants from the contextual type would need to be appended to those)RyanCavanaugh commentedon Dec 1, 2020
Tagging backlog since this is a longstanding shortcoming, but we can take it earlier if someone's eager to take a stab.
safareli commentedon Feb 5, 2021
This is same issue as this one right?
Output
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
safareli commentedon Feb 5, 2021
Sort of a "solution" is to do this:
but it's not very nice. (I came across this when I was trying to use discriminated unions for react prop types)
update contextual discrimination to include omitted members (#43633)
Fix contextual discrimination for omitted members (#43937)
Andarist commentedon Apr 28, 2022
Andrew Branch (@andrewbranch) Is this supposed to be still open? This doesn't error in 4.6, see playground
andrewbranch commentedon Apr 28, 2022
Huh, the fix was reverted, so I’m not sure what happened.
typescript-bot commentedon Apr 28, 2022
👋 Hi, I'm the Repro bot. I can help narrow down and track compiler bugs across releases! This comment reflects the current state of the repro in the issue body running against the nightly TypeScript.
Issue body code block by Andrew Branch (@andrewbranch)
❌ Failed: -
Argument of type '{ cb: (n: string) => number; }' is not assignable to parameter of type 'DiscriminatorTrue | DiscriminatorFalse'. Type '{ cb: (n: string) => number; }' is not assignable to type 'DiscriminatorFalse'. Types of property 'cb' are incompatible. Type '(n: string) => number' is not assignable to type '(x: number) => void'. Types of parameters 'n' and 'x' are incompatible. Type 'number' is not assignable to type 'string'.Historical Information
❌ Failed: -
Argument of type '{ cb: (n: string) => number; }' is not assignable to parameter of type 'DiscriminatorTrue | DiscriminatorFalse'. Type '{ cb: (n: string) => number; }' is not assignable to type 'DiscriminatorFalse'. Types of property 'cb' are incompatible. Type '(n: string) => number' is not assignable to type '(x: number) => void'. Types of parameters 'n' and 'x' are incompatible. Type 'number' is not assignable to type 'string'.❌ Failed: -
Parameter 'n' implicitly has an 'any' type.Argument of type '{ cb: (n: string) => number; }' is not assignable to parameter of type 'DiscriminatorTrue | DiscriminatorFalse'. Type '{ cb: (n: string) => number; }' is not assignable to type 'DiscriminatorFalse'. Types of property 'cb' are incompatible. Type '(n: string) => number' is not assignable to type '(x: number) => void'. Types of parameters 'n' and 'x' are incompatible. Type 'number' is not assignable to type 'string'.andrewbranch commentedon Apr 28, 2022
Hm, so it seems like #43633 originally fixed this but caused a crash and was reverted, and then #43937 promptly fixed it again and caused a performance regression that has not been reverted or fixed 😕
luxaritas commentedon Mar 4, 2023
Anyone know the state of this? Is it worth a new issue? Looks to exist in 4.9.5
weswigham commentedon Mar 22, 2023
The OP's issue is still fixed, so if you have something that seems similar, definitely file a new bug.