Skip to content

Weird behaviour with union types and 'strict' object literals #5237

Description

I'm not sure if this a bug or by design, but it's confusing me:

interface Constraint {
  message?: string;
}

var badConstraint: Constraint = {
  messge: "rte" // errors as expected
};

var goodConstraint: Constraint | boolean = {
  messge: "rte" // I expect this to error!
};

Can anybody explain what is going on here?

http://www.typescriptlang.org/Playground/#src=interface%20Constraint%20%7B%0D%0A%20%20message%3F%3A%20string%3B%0D%0A%7D%0D%0A%0D%0Avar%20badConstraint%3A%20Constraint%20%3D%20%7B%0D%0A%20%20messge%3A%20%22rte%22%20%2F%2F%20errors%20as%20expected%0D%0A%7D%3B%0D%0A%0D%0Avar%20goodConstraint%3A%20Constraint%20%7C%20boolean%20%3D%20%7B%0D%0A%20%20messge%3A%20%22rte%22%20%2F%2F%20I%20expect%20this%20to%20error!%0D%0A%7D%3B%0D%0A

Activity

  1. jonnystoten commented on Oct 13, 2015

    @jonnystoten
    Author

    In fact, changing boolean to Boolean fixes the problem. Is this something to do with primitives in union types?

  2. RyanCavanaugh commented on Oct 14, 2015

    @RyanCavanaugh
    Member

    Obviously undesirable behavior, but it's behaving to the spec as currently written:

    A source type S is considered to have excess properties with respect to a target type T if

    • S is a fresh object literal type, as defined below, and
    • S has one or more properties that aren't expected in T.

    A property P is said to be expected in a type T if one of the following is true:

    • T is not an object, union, or intersection type.
    • T is an object type and
      • T has a property with the same name as P,
      • T has a string or numeric index signature,
      • T has no properties, or
      • T is the global type 'Object'.
    • T is a union or intersection type and P is expected in at least one of the constituent types of T.

    The property messge is "expected" (in the spec sense of the word, not plain English!) in Constraint | boolean because that type "is a union [...] type", and messge is "expected" in boolean because boolean "is not an object, union, or intersection type".

    So we see that the property is "expected" in the target type, and normally this would be OK because we would fail a later assignability check. But instead we successfully assign { messge: string } to { message?: string } because it has all required properties.

    The proposed fix implemented in #3842 would flag this as an error. We should review that fix as it has broader good implications besides this one.

  3. added
    Needs ProposalThis issue needs a plan that clarifies the finer details of how it could be implemented.
    and removed on Oct 19, 2015
  4. RyanCavanaugh commented on Oct 20, 2015

    @RyanCavanaugh
    Member

    Do we have an issue tracking the spec update?

  5. ahejlsberg commented on Oct 20, 2015

    @ahejlsberg
    Member
  6. added
    FixedA PR has been merged for this issue
    and removed
    Needs ProposalThis issue needs a plan that clarifies the finer details of how it could be implemented.
    on Oct 20, 2015
  7. locked and limited conversation to collaborators on Jun 19, 2018
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Labels

FixedA PR has been merged for this issueSuggestionAn idea for TypeScript

Type

No type

Projects

No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions