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

ThisType doesn't work with objects in array #33392

Closed
Akryum opened this issue Sep 12, 2019 · 16 comments
Closed

ThisType doesn't work with objects in array #33392

Akryum opened this issue Sep 12, 2019 · 16 comments
Labels
Working as Intended The behavior described is the intended behavior; this is not a bug

Comments

@Akryum
Copy link

Akryum commented Sep 12, 2019

TypeScript Version: 3.7.0-dev.20190912

Search Terms: thistype array

Code

interface Instance {
  foo: 'bar' | 'baar'
}

type Fn = () => any | any

interface Sub {
  vars: Fn
}

interface Options {
  subs: Sub | Sub[]
}

const meow: Options & ThisType<Instance> = {
  subs: {
    vars () {
      return this.foo === 'bar'
    }
  }
}

const meows: Options & ThisType<Instance> = {
  subs: [
    {
      vars () {
        // Error happens here
        return this.foo === 'bar'
      }
    }
  ]
}

Expected behavior:

No errors.

Actual behavior:

error TS2339: Property 'foo' does not exist on type 'Sub'.

Playground Link:

https://www.typescriptlang.org/play/#code/JYOwLgpgTgZghgYwgAgJIgM5jiJyDeAUMsjAPZkBcyA5AEZxQ3IA+tDjNhAvoYWAE8ADigBiIZAF5kACgCUUgHzIcA1ipAC+oSLEQoAygFc6BYsgBujDNXE9t4aPDwB5IWGBlMZkhhM3kY1M2IIBtAF17QgQvLGQAWwgyAHdqNw9Y5AAyZAAVAAtgDFzhCAAedCwcJGVpIl9-anqSS2tZBWaW5CgIMCMoCTBCjAA6cjIpSWl6TnMSXnmomMwwBKTkgPTPbxyCopKRCpXqiFqfZD86ANC5866rKAx2u67u3v7B4bGKSemGJluiy6C2QkV4QA

Related Issues:

@j-oliveras
Copy link
Contributor

The this inside meows is a reference to the object inside the array, not the object meows. You can test it with node:

var meows = {
  subs: [
    {
      vars () {
        this.foo = 'hello' // assigned to display what is this here
        // Error happens here
        return this.foo === 'bar'
      }
    }
  ]
}
console.log(meows) // { subs: [ { vars: [Function: vars] } ] }
meows.subs[0].vars()
console.log(meows) // { subs: [ { vars: [Function: vars], foo: 'hello' } ] }

@Akryum
Copy link
Author

Akryum commented Sep 12, 2019

It will do the same with:

const meow = {
  subs: {
    vars () {
      this.foo = 'hello'
      return this.foo === 'bar'
    }
  }
}
console.log(meows) // { subs: { vars: [Function: vars] } }
meows.subs.vars()
console.log(meows) // { subs: { vars: [Function: vars], foo: 'hello' } }

That's not the point of this issue, those methods a bound internally by my library.

@fatcerberus
Copy link

Pretty sure ThisType only affects the object directly assigned to it, not sub-objects, whose properties have their own types (and therefore don't inherit the ThisType).

@Akryum
Copy link
Author

Akryum commented Sep 13, 2019

I guess it's necessary, otherwise Vue typings wouldn't work 😁

@RyanCavanaugh RyanCavanaugh added the Working as Intended The behavior described is the intended behavior; this is not a bug label Sep 13, 2019
@RyanCavanaugh
Copy link
Member

@fatcerberus is correct

@weswigham
Copy link
Member

FYI, if you want a deeply bound ThisType, you can do something like

type DeepApplyThisType<T, TThis> = {[K in keyof T]: DeepApplyThisType<T[K], TThis>} & ThisType<TThis>;

but it's on you to make sure your library can actually bind the this's of those functions up to match that.

@Akryum
Copy link
Author

Akryum commented Sep 14, 2019

@RyanCavanaugh I've put a link in this message showing the inconsistency in nested objects.

@typescript-bot
Copy link
Collaborator

This issue has been marked 'Working as Intended' and has seen no recent activity. It has been automatically closed for house-keeping purposes.

@Akryum
Copy link
Author

Akryum commented Sep 19, 2019

Using a custom type DeepApplyThisType breaks other types:

Example

@Akryum
Copy link
Author

Akryum commented Sep 19, 2019

Could the issue be re-open? It causes me a lot of difficulties for vue-apollo typings.

@dragomirtitian
Copy link
Contributor

dragomirtitian commented Sep 20, 2019

@Akryum DeepApplyThisType works but does not cover all cases as it should. It should distribute over T[K] to correctly apply this in a union, and should not perform the transformation on function or primitives. This works with your example:

type DistributionHelper<T, TThis> = T extends Function | string | number | boolean ? T: DeepApplyThisType<T, TThis>

type DeepApplyThisType<T, TThis> = {
  [K in keyof T]: DistributionHelper<T[K], TThis>
} & ThisType<TThis>;

play

Other corner cases may arise but they can probably be solved.

@Akryum
Copy link
Author

Akryum commented Sep 20, 2019

Thanks, will try it

@Akryum
Copy link
Author

Akryum commented Sep 22, 2019

It's still doesn't work, the types are still broken:

Play

No error is thrown here:

const apollo2: DeepApplyThisType<ApolloOptions, Instance> = {
  $client: '42',
  foo: {
    // No error thrown here
    variableeees () {
      return {
        bar: this.foo
      }
    },
    update: (data) => data.foo
  }
}

@Akryum
Copy link
Author

Akryum commented Sep 30, 2019

Please can this be reopen? 😅

@Akryum
Copy link
Author

Akryum commented Feb 11, 2021

💀

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
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

7 participants