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

Discriminated union pattern fails to narrow type with ReturnType and inferenced function type #26730

Closed
mserranom opened this issue Aug 29, 2018 · 2 comments
Labels
Question An issue which isn't directly actionable in code

Comments

@mserranom
Copy link

TypeScript Version: 3.0.1 and 3.1.0-dev.20180829

Search Terms:

Code

type A = {
  type: "A";
  aprop: number;
};

type B = {
  type: "B";
  bprop: number;
};


function aFunc() {
    return { type: "A", aprop: 2 }
};

function bFunc() {
    return { type: "B", bprop: 2 }
};


function aFuncTyped(): A {
    return { type: "A", aprop: 2 }
};

function bFuncTyped(): B {
    return { type: "B", bprop: 2 }
};


// 1. Discriminated with ReturnType of explicitely typed functions: all good.

let x2: ReturnType<typeof aFuncTyped> | ReturnType<typeof bFuncTyped>;

if (x2.type === "A") {
  x2.aprop;
}

if (x2.type === "B") {
  x2.bprop;
}

// 2. Discriminated with ReturnType of implicitely typed functions: errors.

let x3: ReturnType<typeof aFunc> | ReturnType<typeof bFunc>;

if (x3.type === "A") {
  // Property 'aprop' does not exist on type '{ type: string; aprop: number; } | { type: string; bprop: number; }'.
  // Property 'aprop' does not exist on type '{ type: string; bprop: number; }'.
  x3.aprop;
}

if (x3.type === "B") {
  // Property 'bprop' does not exist on type '{ type: string; aprop: number; } | { type: string; bprop: number; }'.
  // Property 'bprop' does not exist on type '{ type: string; aprop: number; }'.
  x3.bprop;
}

Expected behavior:

Should not fail to compile.

ReturnType infers correctly the type of afunc() and bfunc(), however it fails to apply the correct discriminate in the if statements.

Actual behavior:

Fails to compile with the error messages indicated in code.

Playground Link:
https://www.typescriptlang.org/play/#src=type%20A%20%3D%20%7B%0D%0A%20%20type%3A%20%22A%22%3B%0D%0A%20%20aprop%3A%20number%3B%0D%0A%7D%3B%0D%0A%0D%0Atype%20B%20%3D%20%7B%0D%0A%20%20type%3A%20%22B%22%3B%0D%0A%20%20bprop%3A%20number%3B%0D%0A%7D%3B%0D%0A%0D%0A%0D%0Afunction%20aFunc()%20%7B%0D%0A%20%20%20%20return%20%7B%20type%3A%20%22A%22%2C%20aprop%3A%202%20%7D%0D%0A%7D%3B%0D%0A%0D%0A%0D%0Afunction%20bFunc()%20%7B%0D%0A%20%20%20%20return%20%7B%20type%3A%20%22B%22%2C%20bprop%3A%202%20%7D%0D%0A%7D%3B%0D%0A%0D%0A%0D%0Afunction%20aFuncTyped()%3A%20A%20%7B%0D%0A%20%20%20%20return%20%7B%20type%3A%20%22A%22%2C%20aprop%3A%202%20%7D%0D%0A%7D%3B%0D%0A%0D%0Afunction%20bFuncTyped()%3A%20B%20%7B%0D%0A%20%20%20%20return%20%7B%20type%3A%20%22B%22%2C%20bprop%3A%202%20%7D%0D%0A%7D%3B%0D%0A%0D%0A%0D%0A%0D%0A%2F%2F%201.%20Discriminated%20with%20ReturnType%20of%20explicitely%20typed%20functions%3A%20all%20good.%0D%0A%0D%0Alet%20x2%3A%20ReturnType%3Ctypeof%20aFuncTyped%3E%20%7C%20ReturnType%3Ctypeof%20bFuncTyped%3E%3B%0D%0A%0D%0Aif%20(x2.type%20%3D%3D%3D%20%22A%22)%20%7B%0D%0A%20%20x2.aprop%3B%0D%0A%7D%0D%0A%0D%0Aif%20(x2.type%20%3D%3D%3D%20%22B%22)%20%7B%0D%0A%20%20x2.bprop%3B%0D%0A%7D%0D%0A%0D%0A%2F%2F%202.%20Discriminated%20with%20ReturnType%20of%20implicitely%20typed%20functions%3A%20errors.%0D%0A%0D%0Alet%20x3%3A%20ReturnType%3Ctypeof%20aFunc%3E%20%7C%20ReturnType%3Ctypeof%20bFunc%3E%3B%0D%0A%0D%0Aif%20(x3.type%20%3D%3D%3D%20%22A%22)%20%7B%0D%0A%20%20%2F%2F%20Property%20'aprop'%20does%20not%20exist%20on%20type%20'%7B%20type%3A%20string%3B%20aprop%3A%20number%3B%20%7D%20%7C%20%7B%20type%3A%20string%3B%20bprop%3A%20number%3B%20%7D'.%0D%0A%20%20%2F%2F%20Property%20'aprop'%20does%20not%20exist%20on%20type%20'%7B%20type%3A%20string%3B%20bprop%3A%20number%3B%20%7D'.%0D%0A%20%20x3.aprop%3B%0D%0A%7D%0D%0A%0D%0Aif%20(x3.type%20%3D%3D%3D%20%22B%22)%20%7B%0D%0A%20%20%2F%2F%20Property%20'bprop'%20does%20not%20exist%20on%20type%20'%7B%20type%3A%20string%3B%20aprop%3A%20number%3B%20%7D%20%7C%20%7B%20type%3A%20string%3B%20bprop%3A%20number%3B%20%7D'.%0D%0A%20%20%2F%2F%20Property%20'bprop'%20does%20not%20exist%20on%20type%20'%7B%20type%3A%20string%3B%20aprop%3A%20number%3B%20%7D'.%0D%0A%20%20x3.bprop%3B%0D%0A%7D%0D%0A%0D%0A%0D%0A

@AlCalzone
Copy link
Contributor

The type property in the return type of aFunc and bFunc is inferred as string, which is the default for object literals (and in most cases the desired behavior). If you explicitly type the properties with a literal type, the error goes away:

function aFunc() {
    return { type: "A" as "A", aprop: 2 }
};

function bFunc() {
    return { type: "B" as "B", bprop: 2 }
};

Related: #20195
and https://blog.mariusschulz.com/2017/02/04/typescript-2-1-literal-type-widening

@RyanCavanaugh RyanCavanaugh added the Question An issue which isn't directly actionable in code label Aug 29, 2018
@typescript-bot
Copy link
Collaborator

This issue has been marked as 'Question' and has seen no recent activity. It has been automatically closed for house-keeping purposes. If you're still waiting on a response, questions are usually better suited to stackoverflow.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Question An issue which isn't directly actionable in code
Projects
None yet
Development

No branches or pull requests

4 participants