-
Notifications
You must be signed in to change notification settings - Fork 7
incorrect return type #13
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
Comments
Having the exact same issue, it worked in vue-async-computed using the composition style, but not class based. Anyway, here's a workaround for now, cast to unknown and then cast to what you know it is.:
But I would also like to know how to fix this 'properly' and also have no knowledge of decorators :) |
Good question! I actually don't have a good answer. Perhaps @nwtgck (who contributed this decorator) knows? As a bit of a workaround, I suppose you could wrap the async computed property in a normal getter / computed property with a type assertion, something like this:
This takes @DGollings' workaround, and formalizes it a bit in a separate getter which passes through the value of the async computed property with a type assertion. This is an unfortunate amount of boilerplate: |
Further improving on above suggestions, below is a generic @Component({})
export default class MyPage extends Vue {
//// Reusable function
// Casts an Async computed field to its synchronous return value
$asyncUnwrap<T>(promise: () => Promise<T>): T {
return (promise as unknown) as T
}
//// Example usage
// Given an async computed property
@AsyncComputed()
async users(): Promise<UserDto[] | undefined> {
return await fetch(`http://example.com/users` ).then(response => response.data.users)
// Re-using the property in another computed property
get userCount() {
return this.$asyncUnwrap(this.users)?.length
} You could place this method in a component base class (and extend from it instead of Vue), or write a small plugin. PluginPlugin to make this method available in all Vue components
function asyncUnwrap<T>(promise: () => Promise<T>): T {
return (promise as unknown) as T
}
declare module 'vue/types/vue' {
interface Vue {
$asyncUnwrap: typeof asyncUnwrap
}
}
export const AsyncUnwrapModule = {
// eslint-disable-next-line @typescript-eslint/no-unused-vars,@typescript-eslint/no-explicit-any
install: (Vue: any, options: any) => {
Vue.prototype.$asyncUnwrap = asyncUnwrap
},
}
// install
Vue.use(AsyncUnwrapModule); usage: // Inside a component function
this.$asyncUnwrap(this.someAsyncComputedProperty); |
After re-consideration, I realize the plugin approach is overkill, since the method can be static. I suggest the following instead. Global $asyncUnwrap method
// noinspection JSUnusedGlobalSymbols
export default function $asyncUnwrap<T>(promise: () => Promise<T>): T {
return (promise as unknown) as T
} usage: import $asyncUnwrap from '@/util/async-unwrap'
@Component
export default class MyPage extends Vue {
@AsyncComputed()
async users(): Promise<User[] | undefined> {
return fetch(/* ... */);
}
get userCount(): number | undefined {
return $asyncUnwrap(this.users)?.length;
}
} |
Using @boukeversteegh unwrap function, i created this plugin which provides a method on the Vue instance. /// asyncUnwrap.ts
import _Vue from "vue";
/**
* Type declaration for the new Vue attribute
*/
declare module 'vue/types/vue' {
interface Vue {
$asyncUnwrap<T>(promise: () => Promise<T>): T
}
}
/**
* Unwraps the type of the promise used in @AsyncComputed decorator & computed property annotations.
* @param Vue
* @param options
*/
export default function AsyncUnwrapPlugin(Vue: typeof _Vue, options?: any): void {
Vue.prototype.$asyncUnwrap = function<T>(promise: () => Promise<T>): T {
return (promise as unknown) as T
};
} Then in main.ts: import AsyncUnwrapPlugin from "./plugins/asyncUnwrap"
Vue.use(AsyncUnwrapPlugin) |
Hm yeah, it's what I went with at first as well, but I didn't like to write In general, after working with Define two properties:
Motivation:
Component()
class MyVueComponent extends Vue {
@AsyncComputed()
async usersAsync(): Promise<User[]> {
return await // ...
}
get users(): User[] {
return $asyncUnwrap(this.usersAsync);
}
} |
Hi, thanks for your work on this - really makes life easier.
I've absolutely no idea about decorators or whether it's even possible, but atm I'm unable to use async computed properties outside of templates because at the moment typescript believes they're a method returning a promise. e.g:
The first computed property will, in-fact, work just fine if I force typescript to ignore it, and the second async property will obviously fail although ts is fine with it:
The text was updated successfully, but these errors were encountered: