这已经成为一个相当长的答案。如果您没有时间阅读全部内容,可以阅读TL;DR在最后.
Analysis
错误信息
一开始我不太明白为什么 TypeScript 会提到VueClass<Vue>
并抱怨template
财产。然而,当我查看类型定义时Component
装饰器,事情变得更加清晰了:
vue-class-component/lib/index.d.ts https://unpkg.com/browse/vue-class-component@7.1.0/lib/index.d.ts(省略部分)
declare function Component<V extends Vue>(options: ComponentOptions<V> & ThisType<V>): <VC extends VueClass<V>>(target: VC) => VC;
// ...
declare function Component<VC extends VueClass<Vue>>(target: VC): VC;
我们在这里可以看到的是Component
有两个签名。第一个像你一样使用,第二个没有选项(@Component class Foo
).
显然编译器认为我们的用法与第一个签名不匹配,因此它必须是第二个签名。因此我们最终会得到一条错误消息VueClass<Vue>
.
Note:在最新版本(3.6.3)中,TypeScript 实际上会显示更好的错误,说明两个重载以及它们不匹配的原因。
更好的错误消息
我做的下一件事是暂时注释掉第二个函数声明main-project/node_modules/vue-class-component
果然我们收到了不同的错误消息。新消息跨越 63 行,因此我认为将其作为一个整体包含在这篇文章中是没有意义的。
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 '{ [key: string]: VueConstructor<Vue> | FunctionalComponentOptions<any, PropsDefinition<any>> | ComponentOptions<never, any, any, any, any, Record<string, any>> | AsyncComponentPromise<any, any, any, any> | AsyncComponentFactory<...>; }'.
Property 'SimpleCheckbox' is incompatible with index signature.
Type 'typeof SimpleCheckbox' is not assignable to type 'VueConstructor<Vue> | FunctionalComponentOptions<any, PropsDefinition<any>> | ComponentOptions<never, any, any, any, any, Record<string, any>> | AsyncComponentPromise<any, any, any, any> | AsyncComponentFactory<...>'.
Type 'typeof SimpleCheckbox' is not assignable to type 'VueConstructor<Vue>'.
Types of property 'extend' are incompatible.
Type '{ <Data, Methods, Computed, PropNames extends string = never>(options?: import("/tmp/dependency/node_modules/vue/types/options").ThisTypedComponentOptionsWithArrayProps<import("/tmp/depende...' is not assignable to type '{ <Data, Methods, Computed, PropNames extends string = never>(options?: import("/tmp/main-project/node_modules/vue/types/options").ThisTypedComponentOptionsWithArrayProps<import("/tmp/main-...'.
...
Type 'import("/tmp/dependency/node_modules/vue/types/vnode").ScopedSlotReturnValue' is not assignable to type 'import("/tmp/main-project/node_modules/vue/types/vnode").ScopedSlotReturnValue'.
Type 'VNode' is not assignable to type 'ScopedSlotReturnValue'.
正如您所看到的,错误消息很难阅读,并且并没有真正指出特定的问题。因此,我继续降低项目的复杂性,以便更好地理解问题。
最小的例子
我将为您省去涉及大量试验和错误的整个过程。让我们直接跳到结果。
结构
├─ main-project
│ ├─ node_modules // installed packages listed below (without sub-dependencies)
│ │ [email protected] /cdn-cgi/l/email-protection
│ │ [email protected] /cdn-cgi/l/email-protection
│ │ [email protected] /cdn-cgi/l/email-protection
│ │ [email protected] /cdn-cgi/l/email-protection
│ │ [email protected] /cdn-cgi/l/email-protection
│ │ [email protected] /cdn-cgi/l/email-protection
│ │ [email protected] /cdn-cgi/l/email-protection
│ ├─ SkipProjectInitializationStepPanel.ts
│ ├─ tsconfig.json
│ └─ webpack.config.js
└─ dependency
├─ node_modules // installed packages listed below (without sub-dependencies)
│ [email protected] /cdn-cgi/l/email-protection
└─ 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 {}
当运行这个例子时main-project
with npm run webpack
,我们得到与之前完全相同的错误。任务完成。
发生了什么?
当我删除项目的一部分以将其简化为这个最小的示例时,我学到了一些非常有趣的东西。
您可能已经注意到import 'vuex'
我已经添加到SkipProjectInitializationStepPanel.ts
。在原来的项目中vuex
当然是从不同的地方进口的(例如main-project/Source/ProjectInitializer/Store/Store.ts
)但这对于重现问题并不重要。关键的部分是main-project
进口vuex
and dependency
doesn't.
找出为什么要导入vuex
导致这个问题,我们必须查看类型定义vuex
.
vuex/types/index.d.ts https://unpkg.com/browse/vuex@3.1.1/types/index.d.ts(前几行)
import _Vue, { WatchOptions } from "vue";
// augment typings of Vue.js
import "./vue";
import { mapState, mapMutations, mapGetters, mapActions, createNamespacedHelpers } from "./helpers";
这里我们感兴趣的是第二个import
。该评论实际上已经给了我们提示:增强 Vue.js 的类型.
vuex/types/vue.d.ts https://unpkg.com/browse/vuex@3.1.1/types/vue.d.ts(省略部分)
import { Store } from "./index";
// ...
declare module "vue/types/vue" {
interface Vue {
$store: Store<any>;
}
}
罪魁祸首就在这里。这vuex
类型利用声明合并 https://www.typescriptlang.org/docs/handbook/declaration-merging.html to add $store
to the Vue
的接口vue
。看来这种增强只发生在相同的“本地”类型上node_modules
as vuex
。因为main-project
有增强的Vue
and dependency
有原件,两者不符。
TS装载机
在我所有的测试过程中,我无法仅用以下命令重现问题tsc
。显然ts-loader
做了一些不同的事情导致了这个问题。这可能与使用 Webpack 进行模块解析有关,也可能是完全不同的东西。我不知道。
解决方法
我有一些想法如何解决或解决这个问题。尽管这些不一定是现成的解决方案,而是不同的方法和想法。
Add vuex
to dependency
作为删除vuex
from main-project
这并不是一个真正的选择,我们唯一能做的就是同时实现这两个目标Vue
接口匹配,包括vuex
in dependency
以及。
这里奇怪的是,我能够在我的最小示例中使此修复工作,但不能在原始项目中工作。我还没弄清楚这是为什么。
除此之外,它不是很优雅,您可能必须导入vuex
从您引用的每个文件中main-project
.
使用共享的node_modules
拥有一个共享的node_modules
文件夹意味着两个项目使用相同的vue
所以这个问题就消失了。根据您的要求,以共享相同的方式组织两个项目可能是一个很好的解决方案node_modules
文件夹。您可能还想看看类似的工具Lerna https://lerna.js.org/ or 纱线工作区 https://yarnpkg.com/lang/en/docs/workspaces/这可以帮助解决这个问题。
Consume dependency
作为一个包
你这么说dependency
还不是 [an] npm 依赖项。也许是时候将其合二为一了。与共享类似node_modules
目录这将导致两个项目使用相同的vue
安装应该可以解决问题。
进一步调查
如前所述,这只发生在ts-loader
. Maybe有一些东西可以修复或配置ts-loader
以避免这个问题。
TL;DR
main-project
进口vuex
while dependency
没有。vuex
增强了Vue
接口使用声明合并 https://www.typescriptlang.org/docs/handbook/declaration-merging.html添加一个$store
其财产。现在Vue
来自一个项目不匹配Vue
来自其他导致错误。