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

Type returned not being checked in a function returning an union type #14392

Closed
thitemple opened this issue Mar 1, 2017 · 2 comments
Closed
Labels
Duplicate An existing issue was already created

Comments

@thitemple
Copy link

TypeScript Version: 2.2.1

Code

interface ISomeType { 
    value: string;
}

interface ISomeOtherType { 
    value2?: string;
}

interface IStillSomeOtherType { 
    value3?: string;
}

type TypeOptions = ISomeType | ISomeOtherType | IStillSomeOtherType;

function fn(x: number): TypeOptions {
    if (x % 2 === 0) {
        return {
            value: "even"
        };
    } else if(x % 2 === 1) {
        return "odd";
    }

    return 123;
}

Expected behavior:
TypeScript should check that the returned value is of the three types defined in the type alias TypeOptions

Actual behavior:
Values of a type different from the specified can be returned, such as strings and numbers.

Link to playground

@krryan
Copy link

krryan commented Mar 1, 2017

Unfortunately, this isn't a bug: you are returning valid values for TypeOptions here. Because ISomeOtherType and IStillSomeOtherType have only optional parameters, the empty object {} is a valid value for those interfaces. And since any extension of those interfaces is also valid as a value for those interfaces, that means any extension of {} is valid here. Which is to say, literally anything at all.

TypeScript does not have any way of specifying that you want objects that only have the indicated properties. You are always allowed to use bigger objects.

This is functionally the same problem as in this issue, and @ahejlsberg's comment there may prove useful to you

You might consider giving those interface some unique string literal identifier property. On our project, we call this property kind. So for example you could have:

interface ISomeType { 
    kind: 'some-type';
    value: string;
}

interface ISomeOtherType { 
    kind: 'some-other-type';
    value2?: string;
}

interface IStillSomeOtherType { 
    kind: 'still-some-other-type';
    value3?: string;
}

type TypeOptions = ISomeType | ISomeOtherType | IStillSomeOtherType;

function fn(x: number): TypeOptions {
    if (x % 2 === 0) {
        return {
            kind: 'some-type',
            value: "even"
        };
    } else if(x % 2 === 1) {
        return "odd";
    }

    return 123;
}

Now "odd" and 123 are not valid return values for the function, since they lack a valid kind property.

@thitemple
Copy link
Author

I understand, I thought it was possible to check that at least an empty object was being returned. But I'll use your recommendation with the kind pattern.
Thanks

@RyanCavanaugh RyanCavanaugh added the Duplicate An existing issue was already created label Mar 7, 2017
@microsoft microsoft locked and limited conversation to collaborators Jun 19, 2018
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
Duplicate An existing issue was already created
Projects
None yet
Development

No branches or pull requests

3 participants