Quasar: For help! Custom quasar perfetch reports an error

Created on 8 Mar 2020  ·  19Comments  ·  Source: quasarframework/quasar

Hi~ For help!

package.json
"@quasar/app": "^1.6.0",
"@quasar/extras": "^1.5.2",
"quasar": "^1.9.8"
"typescript": "^3.8.3"

quasar.conf.js
supportTS: true
preFetch: true

Previously there were no errors with the @quasar/typescript plug-in

企业微信截图_15836745205238
企业微信截图_15836745934920

thx!

Most helpful comment

Let's keep this open until the related PR is merged :)

All 19 comments

@IlCallo can you clarify here pls? Thx.

For the first screenshot, TS is inferring your promises as returning unknown (and they return an array, because that's what Promise.all do), it's up to you to make it infer void or force it with a type cast.

I cannot understand what you're asking about the second screenshot, can you explain it better?

Without other info I don't really know why you got this error now. Maybe you didn't had strict: true before in your tsconfig?

Always keep in mind that you can override the Quasar TS configuration options by adding them into your tsconfig.json

quasar/app 1.6 build-in TS
img 1: Return not supported Promisi.all
img 2: Try to customize the prefetch interface

plug-in @quasar/typescript My custom interface is fine

Sorry, my English is not very good (╥﹏╥)

tsconfig.json

{
  "extends": "@quasar/app/tsconfig-preset",
  "compilerOptions": {
    "target": "es5",
    "module": "esnext",
    "strict": true,
    "allowJs": true,
    "jsx": "preserve",
    "importHelpers": true,
    "moduleResolution": "node",
    "experimentalDecorators": true,
    "esModuleInterop": true,
    "downlevelIteration": true,
    "allowSyntheticDefaultImports": true,
    "sourceMap": true,
    "baseUrl": ".",
    "types": [
      "quasar"
    ],
    "paths": {
      "@/*": [
        "src/*"
      ]
    },
    "lib": [
      "esnext",
      "dom",
      "dom.iterable",
      "scripthost"
    ]
  },
  "include": [
    "./src/**/*"
  ]
}

customize the prefetch interface

export interface PreFetchOption {
  store: STORE
  ssrContext: SSRContext
  currentRoute: Route
  redirect: Function
}
declare module 'vue/types/options' {
  interface ComponentOptions {
    preFetch?: (options: PreFetchOption) => void | Promise,
    meta?: object | ((this: V) => object)
  }
}

Problem 1
Because of how Promise.all is typed, it will always return a promise of an array, while we expect a Promise<void>.
There are multiple solutions:

  • you can cast the promise to be the one we need like this
  preFetch(context) {
    return Promise.all([
      new Promise((res, rej) => {
        res();
      })
    ]) as unknown as Promise<void>;
  },
  • you can use async/await to reduce the type to Promise<void> like this
  async preFetch(context) {
    await Promise.all([
      new Promise((res, rej) => {
        res();
      })
    ]);
  },
  • we can change the accepted return type to Promise<{}>, which will accept pretty much everything (even void[] and unknown[])

Source: https://stackoverflow.com/questions/43597503/type-void-array-not-assignable-to-type-void

Problem 2
That's just standard TypeScript stuff: you cannot augment an already defined method with a conflicting interface.
Anyway you pointed me out that the context has not been typed properly, I'll fix that :)

thx~

Let's keep this open until the related PR is merged :)

hi, I try your example

 async preFetch(context) {
    await Promise.all([
      new Promise((res, rej) => {
        res();
      })
    ]);
  },

this got error "Type 'Promise<void>' is not assignable to type 'Promise<{}>'."
maybe add it on ?
Screen Shot 2020-04-22 at 1 48 21 PM

And where I should put <TStore> define ?
Screen Shot 2020-04-22 at 1 58 21 PM
Screen Shot 2020-04-22 at 1 58 50 PM

thx!

@wowissu hey!
I checked and something is definitly not working.
I'll add Promise<void> as possible return type.

On the usage, it's true that generics cannot be used in that way because of syntactic limitations of TS.
Unluckily, the only way I came up with, given that it's an augmentation of Vue options types, is to use a wrapper function to make it work.
You can test this pattern adding

type PrefetchCallback<TStore = any> = (
  options: PreFetchOptions<TStore>
) => void | Promise<void> | Promise<{}>;

function preFetch<TStore>(callback: PrefetchCallback<TStore>) {
  return callback;
}

export default defineComponent({
  // ...
  preFetch: preFetch<{ prop1: string }>(({store}) => {
    // ...
  })
  // ...
});

Tell me what do you think

For Vue 2.x this is pretty much all we can offer, even Vuex augmentation is nothing more than a

declare module "vue/types/options" {
  interface ComponentOptions<V extends Vue> {
    store?: Store<any>;
  }
}

Because we cannot add a new generic into an augmentation and we are forced to use the augmentation to add a Vue option

declare module "vue/types/options" {
  interface ComponentOptions<V extends Vue> {
    // https://github.com/quasarframework/quasar/issues/6576#issuecomment-603787603
    // Promise<{}> allow nearly any type of Promise to be used
    preFetch?: (options: PreFetchOptions<Vue['$store']>) => void | Promise<void> | Promise<{}>;
  }
}

maybe ?

Unless I'm missing something, that won't help.
As I wrote in my previous comment you'd just get the Store<any> type, due to Vuex typings

I follow your way and

image

Am I missing something ?

I probably also changed something into @quasar/app :thinking:
Can you replicate locally the changes I did in the PR?

Fix will be available with "quasar" v1.9.16.

hi~ I'm back again. :)
The upgrade to Typescript 3.9.3

image

{
 "typescript": "3.9.3", 
 "@quasar/app": "1.9.5",
 "quasar": "1.12.2"
}

ERROR in /mnt/f/Teleone-Frontend/Vue-Typescript-Quasar-sample/node_modules/@quasar/app/types/boot.d.ts(1,23):
TS2724: Module '"quasar"' has no exported member 'HasStoreParam'. Did you mean 'HasSsrParam'?
ERROR in /mnt/f/Teleone-Frontend/Vue-Typescript-Quasar-sample/node_modules/@quasar/app/types/configuration.d.ts(1,10):
TS2724: Module '"quasar"' has no exported member 'QuasarContext'. Did you mean 'QSsrContext'?
ERROR in /mnt/f/Teleone-Frontend/Vue-Typescript-Quasar-sample/node_modules/@quasar/app/types/configuration.d.ts(1,25):
TS2305: Module '"quasar"' has no exported member 'QuasarConf'

@a599155162 Do not manually add "typescript" dependency on your own. Let Quasar handle it.
v3.9.x has some bugs that were not yet fixed. So we are running with v3.8.3

@rstoenescu thx~

Was this page helpful?
0 / 5 - 0 ratings