记录一下 vue3+typescript 开发公共组件的注意事项
我的项目构造
|-- examples 搁置用于测试组件的代码
| |-- App.vue
| |-- main.ts
|-- packages 搁置组件的代码
| |-- index.ts
| |-- shims-vue.d.ts
| |-- assets
| | |-- logo.png
| |-- components
| |-- helloWorld
| |-- HelloWorld.tsx 组件的定义
| |-- index.ts 组件裸露以及全局申明
|-- public
| |-- favicon.ico
| |-- index.html
|-- tests
| |-- unit
| |-- example.spec.ts
|-- .browserslistrc
|-- .eslintrc.js
|-- .gitignore
|-- babel.config.js
|-- jest.config.js
|-- package-lock.json
|-- package.json
|-- README.md
|-- tsconfig.json
|-- vue.config.js
组件编写
组件定义
// packages/components/helloWorld/HelloWorld.tsx
import {defineComponent, type ExtractPropTypes} from "vue";
const props = {
/** 姓名 */
name: String,
/** 年龄 */
age: Number,
};
// ExtractPropTypes:承受一个类型,返回 vue3 解决后的类型
export type HelloWorldProps = ExtractPropTypes<typeof props>;
export default defineComponent({
name: "HelloWorld",
props: props,
emits: ["click"],
setup(props, { emit}) {const onClick = (event: MouseEvent) => {emit("click", event);
};
return () => {
return (
<tag>
<div onClick={onClick}>
HelloWorld, {props.name}, {props.age}
</div>
</tag>
);
};
},
});
组件申明,裸露
// packages/components/helloWorld/index.ts
import HelloWorld from "./HelloWorld";
export {type HelloWorldProps} from "./HelloWorld";
export default HelloWorld;
// 组件调用时,提供代码提醒
declare module "vue" {
export interface GlobalComponents {HelloWorld: typeof HelloWorld;}
}
组件注册
// packages/index.ts
import type {App} from "vue";
import HelloWorld from "./components/helloWorld";
// 定义 install 办法,供内部调用
const install = (Vue: App) => {Vue.component("HelloWorld", HelloWorld);
};
export default {install};
编译插件
npm i -D vue-ts
配置文件
package.json
"scripts": {"lib": "vue-cli-service build --target lib --name xxx --dest lib packages/index.ts && vue-tsc --declaration --emitDeclarationOnly",}
tsconfig.json
{
"compilerOptions": {
"outDir": "lib/types", // 指定编译后的文件门路
"target": "esnext",
"module": "CommonJS",
"strict": true,
"jsx": "preserve",
"moduleResolution": "node",
"skipLibCheck": true,
"esModuleInterop": true,
"allowSyntheticDefaultImports": true,
"forceConsistentCasingInFileNames": true,
"useDefineForClassFields": true,
"sourceMap": true,
"baseUrl": ".",
"types": [
"webpack-env",
"jest"
],
"paths": {
"@/*": ["packages/*"]
},
"lib": [
"esnext",
"dom",
"dom.iterable",
"scripthost"
]
},
"include": [
"packages/**/*.ts",
"packages/**/*.tsx"
],
"exclude": ["node_modules"]
}