Skip to content

Local variables not narrowed in lambda function bodies #15631

@paarthenon

Description

@paarthenon

Hello all, love your work with the language. I suspect I may have found a bug:

Local variables that are a union type (such as type | undefined) at declaration aren't being narrowed in lambda functions. Parameters and local aliases of those variables are.

TypeScript Version: 2.2.2 / 2.3.2 / nightly (2.4.0-dev.20170506)

Code

// A *self-contained* demonstration of the problem follows...

// example type
interface Test {
	label:string
}

// Function operates without errors, 'parameter' is correctly
// narrowed to Test rather than Test|undefined
function testParameters(parameter:Test|undefined) {
	if (parameter) {
		console.log(parameter.label);
		Promise.resolve().then(() => parameter.label);
	}
}

// Local variable is not narrowed in the lambda/arrow
function testLocals(parameter:Test|undefined) {
	let local = parameter;
	if (local) {
		console.log(local.label);
		Promise.resolve().then(() => local.label);
		//^ Error "Object is possibly 'undefined'."
	}
}

// Useful but annoying workaround
function workaround1(parameter:Test|undefined) {
	let local = parameter;
	if (local) {
		let localLabel = local.label;
		console.log(local.label);
		Promise.resolve().then(() => localLabel);
	}
}

// Useful but annoying workaround #2
function workaround2(parameter:Test|undefined) {
	let local = parameter;
	if (local) {
		let localPrime = local;
		console.log(local.label);
		Promise.resolve().then(() => localPrime.label);
	}
}

Expected behavior:

I expect union types to be narrowed in lambda functions defined inside of a block with a type guard.

Actual behavior:

Variables that are narrowed in the block a lambda is created are not interpreted as their narrowed type inside the body of the lambda function. The above examples also apply to union types with truthy variables like number | string and their appropriate type guards and to functions written as function(){...}.

Metadata

Metadata

Assignees

No one assigned

    Labels

    DuplicateAn existing issue was already created

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions