Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

OneOf type for interface without discriminators #23928

Closed
realyze opened this issue May 7, 2018 · 5 comments
Closed

OneOf type for interface without discriminators #23928

realyze opened this issue May 7, 2018 · 5 comments
Labels
Question An issue which isn't directly actionable in code

Comments

@realyze
Copy link

realyze commented May 7, 2018

I have the following type

type OneOf<T, U> = { [P in keyof T]?: never } & U | { [P in keyof U]?: never } & T;

The idea is that I could use it when I have an interface that can have one combination of props or the other (e.g. size: number vs horizontalSize: number; verticalSize: number).

Now, I would think

const getSize = (props: Props) => typeof props.size === 'undefined` ? props.horizontalSize : props.size;

Would have type number but it actually has number | undefined.

Should TypeScript be able to determine that the other "branch" should be used (i.e., size is missing ergo horizontalSize must be defined)?

@mhegazy
Copy link
Contributor

mhegazy commented May 7, 2018

Not sure this type is what you want then. Looks like the type you are looking for is { size: number } | { horizontalSize: number; verticalSize: number; }.

Since the union does not have a discriminant (i.e. a common property with a unit type that is different in each constituent), the only way to narrow it is using in operator:

declare var foo: { size: number } | { horizontalSize: number; verticalSize: number; };

"size" in foo ? foo.size : foo.horizontalSize;

@mhegazy
Copy link
Contributor

mhegazy commented May 7, 2018

You might have better luck sharing this on StackOverflow. This is not a support forum, it is one for reporting compiler/language bugs and suggestions.
If you believe you are running into a compiler bug, please share a minimal repro project that demonstrates the issue you are running into and why you believe this is a compiler bug and not a declaration file issue or library usage problem.

@mhegazy mhegazy added the Question An issue which isn't directly actionable in code label May 7, 2018
@realyze
Copy link
Author

realyze commented May 7, 2018

@mhegazy Thanks for the tip! I didn't want to word the ticket as a bug because I wasn't sure whether that was expected TS behaviour or not; it definitely surprised me.

Using in works as a charm so I'll close this. Thanks again.

@realyze realyze closed this as completed May 7, 2018
@realyze
Copy link
Author

realyze commented May 7, 2018

Actually, apologies for another ping, @mhegazy, but there is a Typescript bug in here I think which surfaces when I use the in syntax:

type Foo = {
  size: number
} | {
  horizontalSize: number;
  verticalSize: number;
};

const bar: Foo = {
  size: 42,
  horizontalSize: 43,
  verticalSize: 44,
};

In the above I would think bar should report an error as Foo is not be allowed to have all three props defined. But it actually compiles fine.

@realyze
Copy link
Author

realyze commented May 7, 2018

Looks like #20863 already tracks that (took me a while to find it).

@microsoft microsoft locked and limited conversation to collaborators Jul 31, 2018
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
Question An issue which isn't directly actionable in code
Projects
None yet
Development

No branches or pull requests

2 participants