Skip to content

typeof operator fails on use-before-defined block scoped variable. #8775

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

Closed
sccolbert opened this issue May 24, 2016 · 7 comments · Fixed by #55283
Closed

typeof operator fails on use-before-defined block scoped variable. #8775

sccolbert opened this issue May 24, 2016 · 7 comments · Fixed by #55283
Labels
Bug A bug in TypeScript Help Wanted You can do this
Milestone

Comments

@sccolbert
Copy link

TypeScript Version:

1.8.0

Code

interface IThing<T> {
    owner: T;
}

var foo = {
    one: null as IThing<typeof foo>, // okay
}

let bar = {
    two: null as IThing<typeof bar>, // fail
}

Expected behavior:

The let definition should compile, since the typeof operator has no runtime effect.

Actual behavior:

The let definition fails with a "used before declaration" error.

@RyanCavanaugh RyanCavanaugh added the Bug A bug in TypeScript label May 24, 2016
@mhegazy mhegazy added this to the Community milestone May 24, 2016
@mhegazy mhegazy added the Help Wanted You can do this label May 24, 2016
@markwongsk
Copy link

Would this be a suitable bug for a first-timer?

@RyanCavanaugh
Copy link
Member

I imagine it will be pretty easy. There are lots of other places where we special-case use of an identifier inside a typeof so there are some examples to work from.

@markwongsk
Copy link

markwongsk commented Aug 1, 2016

I don't think this is a special-casing of typeof. For example, the example above works for a var foo declaration, but not a let bar declaration. Other manifestations of this problem include:

var baz = { 
    one: baz, // valid
};

let ack = { 
    one: ack, // fails
};

var a = [ a ]; // valid
let b = [ b ]; // fails

I think the reason for the differences is the following lines in checker.ts (revision 6e4dd75, line 890):

                if (meaning & SymbolFlags.BlockScopedVariable) {
                    const exportOrLocalSymbol = getExportSymbolOfValueSymbolIfExported(result);
                    if (exportOrLocalSymbol.flags & SymbolFlags.BlockScopedVariable) {
                        checkResolvedBlockScopedVariable(exportOrLocalSymbol, errorLocation);
                    }
                }

Since the let causes the variable to be block-scoped, this eventually triggers the check isImmediatelyUsedInInitializerOfBlockScopedVariable. At this point, I'm wondering if this was an explicit design decision. It seems like under the ECMAScript specification, baz and a are valid whereas ack and b are not, which leads me to want to conclude that the current implementation is correct.

@RyanCavanaugh
Copy link
Member

The runtime behavior is mostly irrelevant to how the type system can behave. There's not anything preventing us from figuring what's going on in a block like this

let a: typeof b;
let b: string;

@markwongsk
Copy link

My understanding of https://github.com/Microsoft/TypeScript/blob/master/doc/spec.md#3.8.10 is that the b in typeof b needs to be typechecked as an identifier reference expression. Am I missing something here?

@markwongsk
Copy link

@RyanCavanaugh sorry if I'm misunderstanding the scope of this fix. But my interpretation of the spec leads me to conclude that this is the correct behavior (as I've explained above). And I wasn't sure a first-timer bug would involve changing the specification.

@DanielRosenwasser
Copy link
Member

@markwongsk just because the entity is being type-checked doesn't mean that TypeScript needs to consider it "used" before its definition in any manner that matters. Like Ryan mentioned, block scoping only matters when used in a value position, but when used as part of a type, there really isn't a reason to impose the restriction.

At best, it seems like the spec leaves it unspecified from what I can see.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Bug A bug in TypeScript Help Wanted You can do this
Projects
None yet
Development

Successfully merging a pull request may close this issue.

5 participants