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 guard does not affect variable inside a function #20901

Closed
srolel opened this issue Dec 26, 2017 · 6 comments
Closed

Type guard does not affect variable inside a function #20901

srolel opened this issue Dec 26, 2017 · 6 comments
Labels
Working as Intended The behavior described is the intended behavior; this is not a bug

Comments

@srolel
Copy link
Contributor

srolel commented Dec 26, 2017

TypeScript Version: 2.7.0-dev.201xxxxx

Code

function foo(o: number | number[]) {
    if (!Array.isArray(o)) {
        o = [o];
    }
    o.length;
    () => o.length;
}

Expected behavior:
No compile errors.

Actual behavior:

Property 'length' does not exist on type 'number'.

in () => o.length

@sylvanaar
Copy link

Note that it occurs with this code too:

function foo(o: number | number[]) {
	if (!Array.isArray(o)) {
		o = [o];
	} else {
		o.length;
		() => o.length; // error: Property 'length' does not exist on type 'number'.
	}
}

@SalathielGenese
Copy link

SalathielGenese commented Dec 27, 2017

I think the TypeScript compiler is using the same scope rules for lambdas and functions. This' the only logical reason I see for this. I think that have to do with Function Statement and Function Expression scope.

A function statement should behave that way because hoisting will make it available in foo top level, not like function expression (and lamdas are always).

Meanwile, though I still can't phatom why @mosho1 wrote it that way, I found that the following works great.

(o => o.length)(o);

@srolel
Copy link
Contributor Author

srolel commented Dec 27, 2017

@SalathielGenese it's a distilled demonstration of the issue, not my use-case. Your solution does not solve the problem because you are assuming the function needs to be called immediately. It may be passed to another function like Array.prototype.map.

Yes, this should be the case for function statements, but not for function expressions and arrow functions.

@SalathielGenese
Copy link

@mosho1, I attempted to :

  1. Explain the reason of the issue,
  2. Provide a workaround

Another workaround could be :

(o: number[]) => o.length

Still another :

() => (<number[]>o).length

All are work around to get the job done while the issue is being fixed.

@ahejlsberg
Copy link
Member

This is working as intended. Type guards remain in effect across function boundaries only when the guarded variable(s) are considered constant. This is the case for const local variables and parameters that never occur as assignment targets in the function. See #10357.

@ahejlsberg ahejlsberg added the Working as Intended The behavior described is the intended behavior; this is not a bug label Dec 27, 2017
@srolel
Copy link
Contributor Author

srolel commented Dec 27, 2017

I see. That makes sense, thanks!

@srolel srolel closed this as completed Dec 27, 2017
@microsoft microsoft locked and limited conversation to collaborators Jul 3, 2018
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
Working as Intended The behavior described is the intended behavior; this is not a bug
Projects
None yet
Development

No branches or pull requests

4 participants