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

Control flow doesn't recognise undefined check #12600

Closed
donaldpipowitch opened this issue Dec 1, 2016 · 7 comments
Closed

Control flow doesn't recognise undefined check #12600

donaldpipowitch opened this issue Dec 1, 2016 · 7 comments
Assignees
Labels
Committed The team has roadmapped this issue Fixed A PR has been merged for this issue Suggestion An idea for TypeScript

Comments

@donaldpipowitch
Copy link
Contributor

donaldpipowitch commented Dec 1, 2016

TypeScript Version: 2.1.1

Code

interface StdoutValue {
  stdout: string;
  stderr?: undefined;
}

interface StderrValue {
  stdout?: undefined;
  stderr: string;
}
type StreamValue = StdoutValue | StderrValue;

const stream: Array<StreamValue> = [
  { stdout: 'foo' },
  { stderr: 'bar' }
];

console.log(stream.map(value => value.stderr === undefined ? value.stdout.toUpperCase() : value.stderr.toUpperCase()));

Expected behavior:

No error with strict null checks.

Actual behavior:

Thinks value.stdout could be undefined on last line, but this is not possible.

@FranklinWhale
Copy link

Actually not only undefined check is not recognized, null check is not recognized either.

interface Properties {
	"property1"?: string
}
function getMap(): {[index: string]: Properties | null} {
	return {
		"1": {
			"property1": "test"
		},
		"2": null
	};
}
let map = getMap();
let item1Property1 = "1" in map && map["1"] !== null && "property1" in map["1"] ? map["1"].property1 : null;

The above code cannot be compiled when strictNullChecks is set to true. The following error is returned:

The right-hand side of an 'in' expression must be of type 'any', an object type or a type parameter

@ahejlsberg
Copy link
Member

We currently consider a type a discriminated union only when all of the possible discriminant values have types composed from unit types. Effectively this means that the string and number cannot be part of the discriminant value type. It certainly would be possible to support combinations of unit types and infinite types, although it does add more complexity to the analysis.

@normalser
Copy link

Related: #12457

@mhegazy mhegazy added the Suggestion An idea for TypeScript label Dec 1, 2016
@RyanCavanaugh RyanCavanaugh added the In Discussion Not yet reached consensus label Dec 5, 2016
@RyanCavanaugh RyanCavanaugh added Committed The team has roadmapped this issue and removed In Discussion Not yet reached consensus labels Mar 14, 2017
@RyanCavanaugh
Copy link
Member

Tentative work item to investigate for the 2.4 milestone, approximately.

@eggers
Copy link

eggers commented Aug 24, 2017

Here's another example of a failing case:

declare var maybeNull: number[] | undefined | null;

let isEmpty: boolean | undefined | null = maybeNull === undefined || maybeNull === null
    ? false
    : maybeNull; // Type of maybeNull should be `null | undefined`
// Instead error is:
//  Type 'false | number[]' is not assignable to type 'boolean'.
//  Type 'number[]' is not assignable to type 'boolean'.

@weswigham
Copy link
Member

weswigham commented Aug 25, 2017

@eggers You just have your cases backwards:

declare var maybeNull: number[] | undefined | null;
let isEmpty: boolean | undefined | null = maybeNull === undefined || maybeNull === null
    ? maybeNull // Type of maybeNull _is_ `null | undefined`
    : false;

@ahejlsberg
Copy link
Member

Closing as the original example is no longer an error.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Committed The team has roadmapped this issue Fixed A PR has been merged for this issue Suggestion An idea for TypeScript
Projects
None yet
Development

No branches or pull requests

8 participants