Skip to content

Object literal strictness and unions #4452

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

Closed
sophiajt opened this issue Aug 25, 2015 · 4 comments
Closed

Object literal strictness and unions #4452

sophiajt opened this issue Aug 25, 2015 · 4 comments
Labels
Suggestion An idea for TypeScript Won't Fix The severity and priority of this issue do not warrant the time or complexity needed to fix it

Comments

@sophiajt
Copy link
Contributor

Currently, if I have the following:

function f(a: {c: number }) { }

f({ a: 3, c: 4 });

I get the error that "Argument of type '{ a: number; c: number; }' is not assignable to parameter of type '{ c: number; }'. Object literal may only specify known properties, and 'a' does not exist in type '{ c: number; }'."

Which makes sense, given our recent work on object literal strictness. What I'm not clear about is why this doesn't allow me to get an intuition about union types. For example, this does not error:

function f(a: { a: string } | {c: number }) { }

f({ a: 3, c: 4 });

By inspection, I'd expect the above to give me an error. The object literal I'm passing in matches neither type in the union strictly, and it's arguable the parts it does seem to match are hinting that I'm doing something wrong.

As a user, wouldn't it be my expectation that I'm saying "strictly either an object with a of type string -or- an object of c with type number"?

@danquirk danquirk added the Bug A bug in TypeScript label Aug 25, 2015
@ahejlsberg
Copy link
Member

That's a union type, not an intersection type. But technicalities aside, I understand why you might expect an error. We currently consider a property unknown if it doesn't exist in any of the constituent types in a union or intersection type on the target side. For example, if you specified a property b in your object literal you'd get an error. I can sort of see it both ways and I'm not sure I consider this a bug.

@DanielRosenwasser DanielRosenwasser changed the title Object literal strictness and intersection Object literal strictness and unions Aug 25, 2015
@sophiajt
Copy link
Contributor Author

@ahejlsberg good catch, updated

If we have time, we can chat about this at the design meeting and update the bug after.

@mhegazy mhegazy added this to the TypeScript 1.8 milestone Sep 18, 2015
@mhegazy mhegazy added Suggestion An idea for TypeScript In Discussion Not yet reached consensus labels Oct 6, 2015
@mhegazy mhegazy removed this from the TypeScript 1.7 milestone Oct 6, 2015
@mhegazy mhegazy removed the Bug A bug in TypeScript label Oct 6, 2015
@RyanCavanaugh RyanCavanaugh added Won't Fix The severity and priority of this issue do not warrant the time or complexity needed to fix it and removed In Discussion Not yet reached consensus labels Oct 19, 2015
@RyanCavanaugh
Copy link
Member

Doesn't seem to be anyone hitting this badly in practice and the check we'd have to do to detect this error would be quite expensive.

@denis-sokolov
Copy link

For posterity, I would like to record another instance of this same issue. With TypeScript 2.9.0-dev.20180402 the issue is still present.

The following behavior confused me for a long time. It is a combination of this issue with a slightly confusing {}.

type Union = { name: string } | { age: number } | {};

type Base = {
  // Try commenting out the base prop
  base: boolean;
};

// Try replacing with just Union
function f(parameter: Base & Union) {}

// Notice the age field is invalid, but is not an error
f({ age: "John", base: true });

// Notice the non-existent field is an error
f({ nonExistent: "", base: true });
// Object literal may only specify known properties, and 'nonExistent' does not exist in type 'Base | (Base & { name: string; }) | (Base & { age: number; })'.

(Try in the playground.)

I don’t know which behavior would be most expected, but whatever treats age and nonExistent fields similarly: either both are errors or both are not errors.

Search optimization: empty interface, narrowing, intersection, union, set, known properties.

@microsoft microsoft locked and limited conversation to collaborators Jul 25, 2018
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
Suggestion An idea for TypeScript Won't Fix The severity and priority of this issue do not warrant the time or complexity needed to fix it
Projects
None yet
Development

No branches or pull requests

6 participants