{"id":14973633,"url":"https://github.com/simonzhangiter/vue-typescript-dpapp-demo","last_synced_at":"2025-04-05T04:11:01.626Z","repository":{"id":143947223,"uuid":"113865391","full_name":"SimonZhangITer/vue-typescript-dpapp-demo","owner":"SimonZhangITer","description":":fire: Let's start with TypeScript","archived":false,"fork":false,"pushed_at":"2019-10-11T08:25:14.000Z","size":722,"stargazers_count":624,"open_issues_count":7,"forks_count":145,"subscribers_count":35,"default_branch":"master","last_synced_at":"2025-03-29T03:06:42.958Z","etag":null,"topics":["demo","starter","typescript","vue","vue-router","vuejs2","vuex"],"latest_commit_sha":null,"homepage":"","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/SimonZhangITer.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null}},"created_at":"2017-12-11T13:58:00.000Z","updated_at":"2024-11-18T07:57:03.000Z","dependencies_parsed_at":"2024-01-13T17:59:51.880Z","dependency_job_id":"25b2855f-b74b-4ff7-9520-1bd64a91b57b","html_url":"https://github.com/SimonZhangITer/vue-typescript-dpapp-demo","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/SimonZhangITer%2Fvue-typescript-dpapp-demo","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/SimonZhangITer%2Fvue-typescript-dpapp-demo/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/SimonZhangITer%2Fvue-typescript-dpapp-demo/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/SimonZhangITer%2Fvue-typescript-dpapp-demo/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/SimonZhangITer","download_url":"https://codeload.github.com/SimonZhangITer/vue-typescript-dpapp-demo/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247284949,"owners_count":20913704,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["demo","starter","typescript","vue","vue-router","vuejs2","vuex"],"created_at":"2024-09-24T13:49:07.111Z","updated_at":"2025-04-05T04:11:01.603Z","avatar_url":"https://github.com/SimonZhangITer.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"\n\u003cdiv align=center\u003e\n    \u003cimg src=\"https://p1.meituan.net/dpgroup/60168751a8f4a79ca3c59edffdde00e423571.jpg\" width=\"126\"/\u003e\n    \u003cimg src=\"https://p0.meituan.net/dpgroup/4a48f7ad4e6231c12c44b3422d67008116085.jpg\" width=\"110\"/\u003e\n\u003c/div\u003e\n\n## 功能\n\n- [x] 轮播\n- [x] 搜索\n- [x] 列表\n- [x] 懒加载\n- [x] 简单动画\n- [x] loading\n- [x] vue-router.ts\n- [x] vuex.ts\n- [x] vue-class-component使用\n- [x] vuex-class使用\n- [x] xxx.d.ts声明文件\n- [x] 基于类的编写方式\n- [x] mock数据\n- [x] tsconfig.json\n- [x] webpack配置\n- [x] \u003cb\u003evue-typescript-cli\u003c/b\u003e\n\n## 完成后的简单例子\n基于类的写法加上静态类型检查，简直不能再嗨\n\n```javascript\n\u003cscript lang=\"ts\"\u003e\nimport Vue from \"vue\";\nimport Component from \"vue-class-component\";\nimport { State } from \"vuex-class\";\n\n@Component\nexport default class Shops extends Vue {\n  @State shops: StoreState.shop[];\n  @State searchVal: string;\n\n  get shopList(): StoreState.shop[] {\n    const shops = this.shops;\n    const searchVal = this.searchVal;\n    return shops.filter(\n      (el: StoreState.shop) =\u003e el.shopName.indexOf(searchVal) \u003e -1\n    );\n  }\n}\n\u003c/script\u003e\n```\n\n# 为什么使用TypeScript\n\n### 1. JavaScript的超集\n支持所有原生JavaScript的语法\n### 2. 强类型语言\n现在很多主流语言都是强类型的，而这点也一直是JavaScript所被人诟病的地方。使用TypeScript之后，将会在代码调试、重构等步骤节省很多时间。\n\n\u003e 比如说：函数在返回值的时候可能经过复杂的操作，那我们如果想要知道这个值的结构就需要去仔细阅读这段代码。那如果有了TypeScript之后，直接就可以看到函数的返回值结构，将会非常的方便\n\n### 3. 强大的IDE支持\n现在的主流编辑器如`VSCode`、`WebStorm`、`Atom`、`Sublime`等都对TypeScript有着非常友好的支持，主要体现在智能提示上，非常的方便\n### 4. 可运行于任何浏览器、计算机、操作系统\n强大的编译引擎\n### 5. 迭代更新快\n不断更新，提供更加方便友好的Api\n### 6. 微软和Google爸爸\nTypeScript是微软开发的语言，而Google的`Angular`使用的就是TypeScript，所以不用担心会停止维护，至少在近几年内TypeScript都会一门主流开发语言\n### 7. npm下载量非常高\n截止2017.12.17, TypeScript在全球范围内的npm日均下载量在`30w`左右，这个数字将近是vue下载量的10倍，可见TypeScript还是非常受欢迎的\n\n# Vue-TypeScript-Cli\n官方虽然明确提出对TypeScript的支持，但是并没有明确的配置文档，自己在配置的时候还是需要查阅很多资料以及踩很多坑的（这个过程真的很蓝瘦-_-）\n\n但是现在可以不用踩这个坑啦，我基于官方的`vue-cli`写了一个[vue-typescript-cli](https://github.com/SimonZhangITer/vue-typescript-template)，可以一键构建TypeScript模板\n\n### 用法\n\n```bash\nvue init SimonZhangITer/vue-typescript-template \u003cproject-name\u003e\n```\n\n比如\n\n```bash\nvue init SimonZhangITer/vue-typescript-template my-project\n```\n然后配置好的TypeScript模板就下载到`./my-project`文件夹了，`npm run dev`即可运行\n# TypeScript配置\n这里记录一下当时的踩坑过程，所有配置已经在[vue-typescript-template](https://github.com/SimonZhangITer/vue-typescript-template)配置完毕\n\n## 1. Webpack\n\n#### 安装ts-loader\n首先需要安装`ts-loader`，这是TypeScript为Webpack提供的编译器，类似于`babel-loader`\n\n```bash\nnpm i ts-loader -D\n```\n\n#### 配置rules\n接着在Webpack的`module.rules`里面添加对ts的支持(我这里的webpack版本是2.x)：\n\n```javascript\n{\n    test: /\\.vue$/,\n    loader: 'vue-loader',\n    options: vueLoaderConfig\n},\n{\n    test: /\\.ts$/,\n    loader: 'ts-loader',\n    options: {\n      appendTsSuffixTo: [/\\.vue$/],\n    }\n}\n```\n#### 配置extensions\n添加可识别文件后缀对ts的支持，如：\n\n```javascript\nextensions: ['.js', '.vue', '.json', '.ts']\n```\n\n\n## 2. tsconfig.json\n\n创建tsconfig.json文件，放在根目录下，和`package.json`同级\n\n配置内容主要也看个人需求，具体可以去typescript的官网查看，但是有一点需要注意：\n\u003e 在Vue中，你需要引入 strict: true (或者至少 noImplicitThis: true，这是 strict 模式的一部分) 以利用组件方法中 this 的类型检查，否则它会始终被看作 any 类型。\n\n这里列出我的配置，功能在注释中给出\n\n```javascript\n{\n  \"include\": [\n    \"src/*\",\n    \"src/**/*\"\n  ],\n  \"exclude\": [\n    \"node_modules\"\n  ],\n  \"compilerOptions\": {\n    // types option has been previously configured\n    \"types\": [\n      // add node as an option\n      \"node\"\n    ],\n    // typeRoots option has been previously configured\n    \"typeRoots\": [\n      // add path to @types\n      \"node_modules/@types\"\n    ],\n    // 以严格模式解析\n    \"strict\": true,\n    // 在.tsx文件里支持JSX\n    \"jsx\": \"preserve\",\n    // 使用的JSX工厂函数\n    \"jsxFactory\": \"h\",\n    // 允许从没有设置默认导出的模块中默认导入\n    \"allowSyntheticDefaultImports\": true,\n    // 启用装饰器\n    \"experimentalDecorators\": true,\n    \"strictFunctionTypes\": false,\n    // 允许编译javascript文件\n    \"allowJs\": true,\n    // 采用的模块系统\n    \"module\": \"esnext\",\n    // 编译输出目标 ES 版本\n    \"target\": \"es5\",\n    // 如何处理模块\n    \"moduleResolution\": \"node\",\n    // 在表达式和声明上有隐含的any类型时报错\n    \"noImplicitAny\": true,\n    \"lib\": [\n      \"dom\",\n      \"es5\",\n      \"es6\",\n      \"es7\",\n      \"es2015.promise\"\n    ],\n    \"sourceMap\": true,\n    \"pretty\": true\n  }\n}\n```\n\n## 3. 修改main.js\n1. 把项目主文件`main.js`修改成`main.ts`，里面的写法基本不变，但是有一点需要注意：\n引入Vue文件的时候需要加上`.vue`后缀,否则编辑器识别不到\n\n2. 把webpack的entry文件也修改成`main.ts`\n\n## 4. vue-shims.d.ts\nTypeScript并不支持Vue文件，所以需要告诉TypeScript`*.vue`文件交给vue编辑器来处理。解决方案就是在创建一个vue-shims.d.ts文件，建议放在src目录下再创建一个`typings`文件夹，把这个声明文件放进去，如：`src/typings/vue-shims.d.ts`，文件内容：\n\n\u003e `*.d.ts`类型文件不需要手动引入，TypeScript会自动加载\n\n```javascript\ndeclare module '*.vue' {\n  import Vue from 'vue'\n  export default Vue\n}\n```\n\n到这里TypeScript在Vue中配置就完成了，可以愉快的撸代码了~\n\n# 第三方插件库\n现在Vue官方已经明确提出支持TypeScript，并考虑出一个对应的`vue-cli`，在这之前，Vue开发团队已经开发出了一些插件库来支持TypeScript，这里简单和大家介绍一下。\n\n### Vue-Class-Component\n[vue-class-component](https://github.com/vuejs/vue-class-component)是官方维护的TypeScript装饰器，写法比较扁平化。Vue对其做到完美兼容，如果你在声明组件时更喜欢基于类的 API，这个库一定不要错过\n\nps：用了这个装饰器之后写方法不需要额外加逗号，贼嗨~~~\n\n```javascript\nimport Vue from \"vue\";\nimport Component from \"vue-class-component\";\n\n@Component\nexport default class App extends Vue {\n  name:string = 'Simon Zhang'\n\n  // computed\n  get MyName():string {\n    return `My name is ${this.name}`\n  }\n\n  // methods\n  sayHello():void {\n    alert(`Hello ${this.name}`)\n  }\n\n  mounted() {\n    this.sayHello();\n  }\n}\n```\n这个代码如果用原生Vue语法来写的话就是这样：\n\n```javascript\nexport default {\n  data () {\n    return {\n      name: 'Simon Zhang'\n    }\n  },\n\n  mounted () {\n    this.sayHello()\n  },\n\n  computed: {\n    MyName() {\n      return `My name is ${this.name}`\n    }\n  },\n\n  methods: {\n    sayHello() {\n      alert(`Hello ${this.name}`)\n    },\n  }\n}\n```\n\n### Vuex-Class\n[vuex-class](https://github.com/ktsn/vuex-class)是基于基于`vue-class-component`对Vuex提供的装饰器。它的作者同时也是`vue-class-component`的主要贡献者，质量还是有保证的。\n\n```javascript\nimport Vue from \"vue\";\nimport Component from \"vue-class-component\";\nimport { State, Action, Getter } from \"vuex-class\";\n\n@Component\nexport default class App extends Vue {\n  name:string = 'Simon Zhang'\n  @State login: boolean;\n  @Action initAjax: () =\u003e void;\n  @Getter load: boolean;\n\n  get isLogin(): boolean {\n    return this.login;\n  }\n\n  mounted() {\n    this.initAjax();\n  }\n}\n```\n上面的代码就相当于：\n\n```javascript\nexport default {\n  data() {\n    return {\n      name: 'Simon Zhang'\n    }\n  },\n\n  mounted() {\n    this.initAjax()\n  },\n\n  computed: {\n    login() {\n      return this.$store.state.login\n    },\n    load() {\n      return this.$store.getters.load\n    }\n  },\n\n  methods: {\n    initAjax() {\n      this.$store.dispatch('initAjax')\n    }\n  }\n}\n```\n\n### Vue-Property-Decorator\n[vue-property-decorator](https://github.com/kaorun343/vue-property-decorator) 是在 vue-class-component 上增强了更多的结合 Vue 特性的装饰器，新增了这 7 个装饰器\n\n- `@Emit`\n- `@Inject`\n- `@Model`\n- `@Prop`\n- `@Provide`\n- `@Watch`\n- `@Component` (从 vue-class-component 继承)\n\n# 坑\n### 引入部分第三方库的时候需要额外声明文件\n比如说我想引入`vue-lazyload`,虽然已经在本地安装，但是typescript还是提示找不到模块。原因是typescript是从`node_modules/@types`目录下去找模块声明，有些库并没有提供typescript的声明文件，所以就需要自己去添加\n\n解决办法：在`src/typings`目前下建一个`tools.d.ts`文件，声明这个模块即可\n\n```javascript\ndeclare module 'vue-awesome-swiper' {\n  export const swiper: any\n  export const swiperSlide: any\n}\n\ndeclare module 'vue-lazyload'\n```\n\n### 对vuex的支持不是很好\n在TypeScript里面使用不了mapState、mapGetters等方法，只能一个变量一个变量的去引用，这个要麻烦不少。不过使用`vuex-class`库之后，写法上也还算简洁美观\n\n```javascript\nexport default class modules extends Vue {\n  @State login: boolean; // 对应this.$store.state.login\n  @State headline: StoreState.headline[]; // 对应this.$store.state.headline\n\n  private swiperOption: Object = {\n    autoplay: true,\n    loop: true,\n    direction: \"vertical\"\n  };\n\n  logoClick(): void {\n    alert(\"点我干嘛\");\n  }\n}\n```\n\n# 项目截图\n\u003cdiv align=center\u003e\n    \u003cimg src=\"https://p1.meituan.net/dpgroup/ffe7312edf899bdaa71e42ae2cff7293124895.png\" width=\"266\"/\u003e\n    \u003cimg src=\"https://p1.meituan.net/dpgroup/2ba7ac68cb3bcef937e48a9fcfb64ca7534292.png\" width=\"266\"/\u003e\n    \u003cimg src=\"http://opnxqffe4.bkt.clouddn.com/15135877156970.jpg\" width=\"266\"/\u003e\n\u003c/div\u003e\n\n# 总结\nTypeScript还是非常值得学习和使用一个语言，还是有很多优点的\n\n欢迎大家对我的项目提建议，欢迎Star~\n\nQQ交流群：323743292\n## Build Setup\n\n``` bash\n# 安装依赖\nnpm install\n\n# 启动项目\nnpm run dev\n\n# 打包项目\nnpm run build\n```\n\n\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsimonzhangiter%2Fvue-typescript-dpapp-demo","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fsimonzhangiter%2Fvue-typescript-dpapp-demo","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsimonzhangiter%2Fvue-typescript-dpapp-demo/lists"}