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

typeof this.xxx gives "identifier expected" error. #1554

Closed
vilicvane opened this issue Dec 24, 2014 · 26 comments · Fixed by #43898
Closed

typeof this.xxx gives "identifier expected" error. #1554

vilicvane opened this issue Dec 24, 2014 · 26 comments · Fixed by #43898
Labels
Help Wanted You can do this Suggestion An idea for TypeScript
Milestone

Comments

@vilicvane
Copy link
Contributor

image

Is this by design or a bug?

@giancarloa
Copy link

i would say neither... it's just wrong syntax... try " var copy = typeof (this.data = { });"... having said this, i would not use this code... it's confusing...

@vilicvane
Copy link
Contributor Author

@giancarloa hmm, you shouldn't add those brackets. the code above is just a minimum issue trigger, not code in production, there would be some situations that you may want to use code like this.

here if you take this to anything other than that, it would be fine and no error would be reported. e.g.

class Test {
    static data = {};
    constructor() {
        var copy: typeof Test.data = {};
    }
}

@DanielRosenwasser
Copy link
Member

As per the spec

TypeQueryExpression:
Identifier
TypeQueryExpression.IdentifierName

So this is expected.

I think the reason it isn't allowed is that something like this

function foo() {
    var x: typeof this.x;
}

is perfectly valid, because this more or less has type any. So while it might make sense in a class, it doesn't make sense in any other context unless we had #229.

@vilicvane
Copy link
Contributor Author

@DanielRosenwasser O.O hmm... then hoping you would consider updating the spec. lol.

@DanielRosenwasser
Copy link
Member

It's something to consider; if your members are not private, you can easily get around this with the following in the mean time.

self = this;
var x: typeof self.data;

@NN---
Copy link

NN--- commented Dec 29, 2014

Waiting for this feature.
I think the simplest case should be supported
var a : typeof this.x = 1;

And a recursive typeof member should lead to error.

Thanks.

@RyanCavanaugh RyanCavanaugh added Suggestion An idea for TypeScript In Discussion Not yet reached consensus labels Dec 30, 2014
@RyanCavanaugh
Copy link
Member

Seems like this should just work if we changed the grammar.

@DanielRosenwasser
Copy link
Member

@RyanCavanaugh, but is it appropriate to allow it in the context I gave? It will inevitably lead to people doing so and getting any as their type.

@vilicvane
Copy link
Contributor Author

syntactically correct doesn't have to mean that it should actually make sense, IMO.
a warning could be raised for this cause, though.

@RyanCavanaugh
Copy link
Member

We already let you write typeof foo.bar where foo is of type any, and we already let you write this.x in other dotted-expression positions when the type of this is any. I don't see why their intersection at typeof this.x should merit an exception.

@juanevp
Copy link

juanevp commented Feb 3, 2015

Just to add another use case. Some time ago I made the type definitions for lodash and some of the supported signatures are really aliases for other methods. I had declared them like this:

interface LoDashArrayWrapper<T> {
    rest(): LoDashArrayWrapper<T>;
    rest(
        callback: ListIterator<T, boolean>,
        thisArg?: any): LoDashArrayWrapper<T>;
    rest(n: number): LoDashArrayWrapper<T>;
    rest(pluckValue: string): LoDashArrayWrapper<T>;
    rest(whereValue: {}): LoDashArrayWrapper<T>;

    drop: typeof rest;

    tail: typeof rest;
}

This worked alright with version 1.0 of the compiler. But it doesn't compile any longer. And I don't see any other option besides duplicating the whole set of signatures for each alias as I cannot think of a TypeQueryExpression that expresses this.

@mwisnicki
Copy link

@juanevp How about function interface ?

interface LoDashArrayWrapper<T> {
    rest: LoDashArrayWrapperOperation<T>;
    drop: LoDashArrayWrapperOperation<T>;
    tail: LoDashArrayWrapperOperation<T>;
}

interface LoDashArrayWrapperOperation<T> {
    (): LoDashArrayWrapper<T>;
    (
        callback: ListIterator<T, boolean>,
        thisArg?: any): LoDashArrayWrapper<T>;
    (n: number): LoDashArrayWrapper<T>;
    (pluckValue: string): LoDashArrayWrapper<T>;
    (whereValue: {}): LoDashArrayWrapper<T>;
}

@RyanCavanaugh RyanCavanaugh added Help Wanted You can do this and removed In Discussion Not yet reached consensus labels Apr 27, 2015
@RyanCavanaugh RyanCavanaugh added this to the Community milestone Apr 27, 2015
@RyanCavanaugh
Copy link
Member

Approved. Should be extremely easy fix? Make sure this doesn't cause _this = this emit in arrow functions, though

@Ciantic
Copy link

Ciantic commented Dec 7, 2016

Is this related? I get [ts] Identifier expected. with following:


class UserState {
    @observable state = {
        name : "",
        id : "",
    };

    @action
    changeUser(user: typeof this.state) { // Error is here
        Object.assign(this.state, user);
    }
}

export const userState = new UserState();

It would be useful to be able to use this.state in above case.

@sam-s4s
Copy link

sam-s4s commented Feb 5, 2018

Hmmm I've just run into this problem :(

I'm defining an object in my class.
Then I'm defining another object that has a type param that needs to be the type of the above.

thing = {
    a: 1,
    b: 2
};
multi: CMultiDataset<typeof this.thing>;

In this case it is not appropriate to just change thing to a static variable and say typeof ClassName.thing because it will be different in each instance. Also multi needs to be a class variable, and thus must have its type in class declaration time.

@RyanCavanaugh @DanielRosenwasser @mhegazy sounds like this was thought to be a relatively easy fix? Looks like it's slipped away from attention over the years though... Any chance of it being implemented?

@weswigham
Copy link
Member

weswigham commented Feb 5, 2018

@sam-s4s nowdays you aught to be able to write CMultiDataset<this["thing"]>, instead. Indexed acceses do work with this (a polymorphic one, even), unlike typeof.

@sam-s4s
Copy link

sam-s4s commented Feb 5, 2018

Thanks @weswigham - I did find out that I can do CMultiDataset<ClassName['thing']> which mostly gets me out of trouble :)

I could not find any combination using this that would work though...

@yxliang01
Copy link

@sam-s4s nowdays you aught to be able to write CMultiDataset<this["thing"]>, instead. Indexed acceses do work with this (a polymorphic one, even), unlike typeof.

I have just tried, but it doesn't work in TypeScript 3.4.4 though, @sam-s4s 's one works (ClassName['thing']). I think it might make more sense that this should work, instead of only able to use the "ClassName"?

@vegerot
Copy link

vegerot commented Jun 8, 2020

If I have something like

  public groupByTypes = ['None', 'Foo', 'Bar'] as const;
   
  public groupBy: typeof groupByTypes[number];

What is the proposed workaround? And I cannot make groupByTypes static

@Feofilakt
Copy link

OMG, 7 years old design bug. Ok, see what would be after yet another 7.

@ubershmekel
Copy link
Contributor

ubershmekel commented Apr 25, 2021

My use-case is I'm sending a callback to a library which has the wrong type specialization. I also don't want to have to remember this spot in the code in case these variables ever change their type. So it looks like

  async foundBob(playerTypeLess: any, bobTypeLess: any) {
    const player = playerTypeLess as typeof this.player;
    ^^ ts(2304) Cannot find name 'this'.

I do use this later in that same method. So the error message is a bit misleading. I end up doing the simpler but more fragile:

    const player = playerTypeLess as Player;

@Zzzen
Copy link
Contributor

Zzzen commented Apr 30, 2021

Have you tried const player = playerTypeLess as this['player'] ? @ubershmekel

@royeradames
Copy link

Have you tried const player = playerTypeLess as this['player'] ? @ubershmekel

TS2304: Cannot find name 'this'.

243 selectedPlanFilters? = [] as typeof this["filters"];

@muuvmuuv
Copy link

muuvmuuv commented Oct 1, 2023

I get no errors for this in VS Code but from the Angular compiler. Did anyone has a workaround for TS2304? I would like to have FormGroup.value typed in ngSubmit function with typeof this.formGroup.value.

@Xriuk
Copy link

Xriuk commented Apr 17, 2024

I get no errors for this in VS Code but from the Angular compiler. Did anyone has a workaround for TS2304? I would like to have FormGroup.value typed in ngSubmit function with typeof this.formGroup.value.

More or less the same, it used to work while on Angular 14 (also tried with Angular 15), but with Angular 16 it compiles, then after a save it recompiles partially and this error pops up.

@serious-angel
Copy link

serious-angel commented May 6, 2024

Is an explicit type an option? It seems like a cleaner version. For example, with TypeScript utility type Record (Repl):

type SomeType = Record<string, string>;
//   ^? type SomeType = { [x: string]: string; }

class Test {
    static data1: SomeType = {};
    //     ^? (property) Test.data1: SomeType

    data2: SomeType = {};
    // ^? (property) Test.data2: SomeType

    constructor() {
        let copy1: SomeType = {};
        //  ^? let copy1: SomeType

        let copy2: typeof Test.data1 = {};
        //  ^? let copy2: SomeType

        let copy3: typeof this.data2 = {};
        //  ^? let copy3: SomeType
    }
}

JavaScript Declarations
class Test {
    constructor() {
        this.data2 = {};
        let copy1 = {};
        let copy2 = {};
        let copy3 = {};

    }
}

Test.data1 = {};
type SomeType = Record<string, string>;

declare class Test {
    static data1: SomeType;
    data2: SomeType;
    constructor();
}

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

Successfully merging a pull request may close this issue.