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

Typescript state auto-typing and implicitly has type 'any' because it does not have a type annotation and is referenced directly or indirectly in its own initializer #131

Closed
vmihailenco opened this issue Sep 13, 2019 · 8 comments
Labels
cantfix This issue can't be fixed now.

Comments

@vmihailenco
Copy link

When using TypeScript and vue-cli the following classic example does not compile with TypeScript 3.6.3:

export function useCounter() {
  const state = reactive({
    count: 0,
    double: computed(() => state.count * 2),
  })
  return state
}

because 'state' implicitly has type 'any' because it does not have a type annotation and is referenced directly or indirectly in its own initializer.. I can "fix" it with following code but I wonder if there are better ways without resorting to manually creating a type definition for the state:

export function useCounter() {
  let self: any = null
  const state = reactive({
    count: 0,
    double: computed(() => self.count * 2),
  })
  self = state
  return state
}

After all that is a common case and it does not work as expected...

@dvic
Copy link

dvic commented Sep 14, 2019

I'm encountering the same problem, currently I do something like

interface Counter {
  count: number,
  double: number
}

export function useCounter() {
  const state = reactive({
    count: 0,
    double: computed(() => state.count * 2)
  }) as Counter;
  return state
}

@vmihailenco
Copy link
Author

vmihailenco commented Sep 14, 2019

Yeah, the advantage of that approach is that we can use Counter interface elsewhere when passing state to another function. The problem is obvious - we need to maintain code in 2 places.

Supporting for classes would be neat e.g.:

class Counter {
  count = 0
  double = computed(() => this.count * 2)

  increment() {
    this.count++
  }
}

export function useCounter() {
  const state = reactive(new Counter())
  return state
}

@drewstewart
Copy link

what do you mean you need to maintain code in 2 places? defining types / interfaces describing shape of your data seems completely acceptable.

@liximomo
Copy link
Member

There seems to be no clean way to fix, as TS really can't handle the type of something self referring.

@liximomo liximomo added the cantfix This issue can't be fixed now. label Sep 16, 2019
@lbssousa
Copy link

I think it's better to use ref in this case:

export function useCounter() {
  const count = ref(0)
  const double = computed(() => count.value * 2)

  return {
    count,
    double
  }
}

@liximomo
Copy link
Member

liximomo commented Sep 17, 2019

Good news, TS 3.7 will support Recursive Type References.

@liximomo
Copy link
Member

@vmihailenco What do you mean that "class is not supported"?

@vmihailenco
Copy link
Author

vmihailenco commented Sep 17, 2019

I mean that following does not work for me:

class Counter {
  count = 0
  double = computed(() => this.count * 2)

  increment() {
    this.count++
  }
}

export function useCounter() {
  const state = reactive(new Counter())
  return state
}

function useSomeHook(state: Counter) {} // <- solved

When calling increment this seems to be null/undefined. I did not try, but computed is likely broken too. I tried naive fix like state.increment.bind(state) but it did not work out.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
cantfix This issue can't be fixed now.
Projects
None yet
Development

No branches or pull requests

5 participants