vuejs / core

🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
https://vuejs.org/
MIT License
47.69k stars 8.33k forks source link

TypeScript error when using enum as default value for a prop in a generic component. #9257

Open DawidKopys opened 1 year ago

DawidKopys commented 1 year ago

Vue version

3.3.4

Link to minimal reproduction

https://stackblitz.com/edit/vitejs-vite-ozff8b?file=src%2Fcomponents%2FGenericComponent.vue

Steps to reproduce

Run npx vue-tsc --noEmit

What is expected?

No TS errors

What is actually happening?

TypeScript error is shown:

❯ npx vue-tsc --noEmit
src/components/GenericComponent.vue:9:5 - error TS2322: Type 'Color.RED' is not assignable to type 'InferDefault<{ color?: T | undefined; }, T | undefined> | undefined'.

9     color: Color.RED,
      ~~~~~

  src/components/GenericComponent.vue:6:5
    6     color?: T;
          ~~~~~
    The expected type comes from property 'color' which is declared here on type 'InferDefaults<{ color?: T | undefined; }>'

Found 1 error in src/components/GenericComponent.vue:9

System Info

System:
    OS: Linux 5.0 undefined
    CPU: (8) x64 Intel(R) Core(TM) i9-9880H CPU @ 2.30GHz
    Memory: 0 Bytes / 0 Bytes
    Shell: 1.0 - /bin/jsh
  Binaries:
    Node: 16.20.0 - /usr/local/bin/node
    Yarn: 1.22.19 - /usr/local/bin/yarn
    npm: 9.4.2 - /usr/local/bin/npm
    pnpm: 8.6.10 - /usr/local/bin/pnpm
  npmPackages:
    vue: ^3.3.4 => 3.3.4

Any additional comments?

Component GenericComponent.vue has one prop - color - which is defined using generic type T with constraint ... extends Color.

Then, this Color enum is used to set the default value of the color prop.

trudbot commented 1 year ago

Generics cannot be used in the way you are doing; in your code, the T is treated as a concrete type.

type Props<T>  = {
  color?: T;
}

withDefaults(
  defineProps<Props<Color>>(),
  {
    color: Color.RED,
  }
);
DawidKopys commented 1 year ago

What do you mean? I can use generics this way according to vue docs here.