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

[BUG] Issue with union and literal types #18365

Closed
fazouane-marouane opened this issue Sep 10, 2017 · 3 comments
Closed

[BUG] Issue with union and literal types #18365

fazouane-marouane opened this issue Sep 10, 2017 · 3 comments
Assignees
Labels
Bug A bug in TypeScript Duplicate An existing issue was already created

Comments

@fazouane-marouane
Copy link

There seems to be a problem with unions and literal types when both types of the union contain a field with the same name.

TypeScript Version: 2.5.2

Code
The small example

class A {
    field: 42;
}

class B {
    field: number;
    otherfield: number;
}

// Gives an error
let x: A | B = {
    field: 42
};
// Type '{ field: number; }' is not assignable to type 'A | B'.
//  Type '{ field: number; }' is not assignable to type 'B'.
//    Property 'otherfield' is missing in type '{ field: number; }'.

The simple example of a more realistic situation (typeorm-ish code)

type OrderBy = 'ASC' | 'DESC';

type SimpleOrderByCondition = {
    name?: OrderBy;
    randomField?: OrderBy;
};

type OrderByCondition = SimpleOrderByCondition | (() => SimpleOrderByCondition);

// Works OK as expected
let orderBy1: OrderByCondition = {
    randomField: 'ASC'
};

// gives an error. But, it should work.
let orderBy2: OrderByCondition = {
    name: 'ASC'
};

Expected behavior:
No error

Actual behavior:

[ts]
Type '{ name: string; }' is not assignable to type 'OrderByCondition'.
Type '{ name: string; }' is not assignable to type '() => SimpleOrderByCondition'.
Type '{ name: string; }' provides no match for the signature '(): SimpleOrderByCondition'.

@olegdunkan
Copy link

olegdunkan commented Sep 10, 2017

First example is about fresh literal object type, check this:

#3823

UPDATE 1: This PR also tightens certain parts of the implementation of union types. Specifically:

We no longer perform subtype reduction on union types but instead perform a non-lossy deduplication of the constituent type set.

class A {
    field: 42;
}

class B {
    field: number;
    otherfield: number;
}

var y: A;

y = {
    field: 42
};

let x: A | B = y; //OK

or

class A {
    field: number; //change type to number and it will be working
}

class B {
    field: number;
    otherfield: number;
}

let x: A | B = {
    field: 42
}; //OK, because type of {field:42} is not {field:42} it is {field:number}, 

Second case is more interesting.
It is the same as above but name is a intrinsic property of function object, The type with property name looks like an candidate for Function type but not the same because it has only name property.
Non-lossy deduplication of the constituent type set may expect all properties of Function to be in object literal.

@mhegazy mhegazy added the Bug A bug in TypeScript label Sep 11, 2017
@mhegazy mhegazy added this to the TypeScript 2.6 milestone Sep 11, 2017
@mhegazy
Copy link
Contributor

mhegazy commented Sep 11, 2017

When a literal is contextually typed by it is base type (number, string, or an enum) we should still infer the literal type. I am sure i have seen this reported before but can not seem to find the issues to reference here.

@mhegazy
Copy link
Contributor

mhegazy commented Oct 9, 2017

Seems like a duplicate of #16457

@mhegazy mhegazy closed this as completed Oct 9, 2017
@mhegazy mhegazy added the Duplicate An existing issue was already created label Oct 9, 2017
@microsoft microsoft locked and limited conversation to collaborators Jun 14, 2018
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
Bug A bug in TypeScript Duplicate An existing issue was already created
Projects
None yet
Development

No branches or pull requests

4 participants