Mateo, parte de este equipo de trabajo, nos ha hecho el favor de redactar esta reseña ya que domina perfectamente dicho tema.
Solución:
Esta se ha convertido en una respuesta bastante larga. Si no tienes tiempo para leerlo todo, hay un TL; DR al final.
Análisis
Mensaje de error
Al principio, realmente no entendía por qué TypeScript mencionaba VueClass
y quejándose de la template
propiedad. Sin embargo, cuando miré las definiciones de tipo para el Component
decorador, las cosas se aclararon un poco:
vue-class-component/lib/index.d.ts
(partes omitidas)
declare function Component(options: ComponentOptions & ThisType): >(target: VC) => VC;
// ...
declare function Component>(target: VC): VC;
Lo que podemos ver aquí es que Component
tiene dos firmas. El primero se utilizará como lo hizo usted, y el segundo sin opciones (@Component class Foo
).
Aparentemente, el compilador cree que nuestro uso no coincide con la primera firma, por lo que debe ser la segunda. Por lo tanto, terminamos con un mensaje de error con VueClass
.
Nota: En la última versión (3.6.3), TypeScript realmente mostrará un error mejor, indicando tanto las sobrecargas como por qué no coinciden.
Mejor mensaje de error
Lo siguiente que hice fue comentar temporalmente la segunda declaración de función en main-project/node_modules/vue-class-component
y, efectivamente, recibimos un mensaje de error diferente. El nuevo mensaje tiene 63 líneas, así que pensé que no tendría sentido incluirlo en esta publicación en su totalidad.
ERROR in /tmp/main-project/InitializeProjectGUI__assets/SingletonComponents/SkipProjectInitializationStepPanel/SkipProjectInitializationStepPanel.ts
../InitializeProjectGUI__assets/SingletonComponents/SkipProjectInitializationStepPanel/SkipProjectInitializationStepPanel.ts
[tsl] ERROR in /tmp/main-project/InitializeProjectGUI__assets/SingletonComponents/SkipProjectInitializationStepPanel/SkipProjectInitializationStepPanel.ts(10,24)
TS2322: Type ' SimpleCheckbox: typeof SimpleCheckbox; ' is not assignable to type ' FunctionalComponentOptions> '.
Property 'SimpleCheckbox' is incompatible with index signature.
Type 'typeof SimpleCheckbox' is not assignable to type 'VueConstructor | FunctionalComponentOptions> | ComponentOptions> | AsyncComponentPromise | AsyncComponentFactory<...>'.
Type 'typeof SimpleCheckbox' is not assignable to type 'VueConstructor'.
Types of property 'extend' are incompatible.
Type '{ (options?: import("/tmp/dependency/node_modules/vue/types/options").ThisTypedComponentOptionsWithArrayProps(options?: import("/tmp/main-project/node_modules/vue/types/options").ThisTypedComponentOptionsWithArrayProps
Como puede ver, el mensaje de error es bastante difícil de leer y realmente no apunta a un problema específico. Entonces, en lugar de eso, seguí adelante y comencé a reducir la complejidad del proyecto para comprender mejor el problema.
Ejemplo mínimo
Te ahorraré todo el proceso que implicó muchas pruebas y errores. Pasemos directamente al resultado.
Estructura
├─ main-project
│ ├─ node_modules // installed packages listed below (without sub-dependencies)
│ │ [email protected]
│ │ [email protected]
│ │ [email protected]
│ │ [email protected]
│ │ [email protected]
│ │ [email protected]
│ │ [email protected]
│ ├─ SkipProjectInitializationStepPanel.ts
│ ├─ tsconfig.json
│ └─ webpack.config.js
└─ dependency
├─ node_modules // installed packages listed below (without sub-dependencies)
│ [email protected]
└─ SimpleCheckbox.ts
main-project/tsconfig.json
"compilerOptions":
"target": "es6",
"strict": true,
"moduleResolution": "node"
main-project/webpack.config.js
:
module.exports =
entry: './SkipProjectInitializationStepPanel.ts',
mode: 'development',
module:
rules: [
test: /.ts$/,
loader: 'ts-loader'
]
,
resolve:
extensions: ['.ts', '.js']
;
main-project/SkipProjectInitializationStepPanel.ts
:
import Component from 'vue-property-decorator';
import 'vuex';
import SimpleCheckbox from '../dependency/SimpleCheckbox';
Component( template: '', components: SimpleCheckbox );
dependency/SimpleCheckbox.ts
:
import Vue from 'vue';
export default class SimpleCheckbox extends Vue
Al ejecutar este ejemplo desde main-project
con npm run webpack
, obtenemos exactamente el mismo error que antes. Misión cumplida.
¿Qué esta pasando?
Mientras eliminaba partes del proyecto para reducirlo a este ejemplo mínimo, aprendí algo muy interesante.
Puede que hayas notado el import 'vuex'
He agregado a SkipProjectInitializationStepPanel.ts
. En el proyecto original vuex
es, por supuesto, importado de diferentes lugares (p. ej. main-project/Source/ProjectInitializer/Store/Store.ts
) pero eso no es importante para reproducir el problema. La parte crucial es que main-project
importaciones vuex
y dependency
no.
Para saber por qué importar vuex
causa este problema, tenemos que mirar las definiciones de tipo de vuex
.
vuex/types/index.d.ts
(primeras líneas)
import _Vue, WatchOptions from "vue";
// augment typings of Vue.js
import "./vue";
import mapState, mapMutations, mapGetters, mapActions, createNamespacedHelpers from "./helpers";
Aquí nos interesa el segundo import
. El comentario ya nos da una pista: aumentar tipificaciones de Vue.js.
vuex/types/vue.d.ts
(partes omitidas)
import Store from "./index";
// ...
declare module "vue/types/vue"
interface Vue
$store: Store;
Y aquí tenemos al culpable. los vuex
los tipos hacen uso de la combinación de declaraciones para agregar $store
al Vue
interfaz de vue
. Parece que este aumento solo ocurre con los tipos "locales" en el mismo node_modules
como vuex
. Porque main-project
tiene el aumentado Vue
y dependency
tiene el original, los dos no coinciden.
Cargador TS
Durante todas mis pruebas no pude reproducir el problema con solo tsc
. Aparentemente ts-loader
hace algo diferente que causa este problema. Podría tener que ver con el uso de Webpack para la resolución del módulo o podría ser algo completamente diferente. No sé.
Enfoques de solución
Tengo algunas ideas sobre cómo resolver o solucionar este problema. Aunque estas no son necesariamente soluciones listas para usar, sino enfoques e ideas diferentes.
Agregar vuex
para dependency
Como remover vuex
de main-project
no es realmente una opción, lo único que podemos hacer para que tanto Vue
las interfaces coinciden, se incluye vuex
en dependency
así como.
Lo extraño aquí es que pude hacer que esta solución funcionara en mi ejemplo mínimo, pero no en el proyecto original. No he descubierto por qué es así.
Además de eso, no es muy elegante y es posible que deba importar vuex
de cada archivo al que hace referencia main-project
.
Utilice un compartido node_modules
Tener un compartido node_modules
carpeta significa que ambos proyectos usan el mismo vue
entonces este problema desaparece. Dependiendo de sus requisitos, puede ser una buena solución organizar los dos proyectos de manera que compartan el mismo node_modules
carpeta. También es posible que desee echar un vistazo a herramientas como los espacios de trabajo de Lerna o Yarn que pueden ayudar con esto.
Consumir dependency
como un paquete
Tu dices eso dependency
no es [an] npm-dependency todavía. Tal vez sea el momento de convertirlo en uno. Similar a un compartido node_modules
directorio, esto daría como resultado que ambos proyectos usen el mismo vue
instalación que debería solucionar el problema.
Investigar más a fondo
Como se mencionó anteriormente, esto solo ocurre con ts-loader
. Quizás hay algo que se puede arreglar o configurar en ts-loader
para evitar este problema.
TL; DR
main-project
importaciones vuex
tiempo dependency
no lo hace. vuex
aumenta el Vue
interfaz usando declaración de fusión agregando un $store
propiedad a ella. Ahora el Vue
de un proyecto no coincide Vue
de otro causando un error.
Si estás contento con lo expuesto, eres capaz de dejar una división acerca de qué te ha impresionado de esta división.