Vue + TypeScript 尝鲜体验
ognm2924
7年前
<p><img src="https://simg.open-open.com/show/63edf72c2b3b3e176b71b28229571205.png"></p> <ul> <li>适用 Vue.version < 2.5 && Vue.version >= 2.2</li> </ul> <p>其实我个人一开始很讨厌 TypeScript 这个东西,就是因为讨厌 Java 的啰里巴嗦,突然在我眼前出现了 JavaScript,便爱上了这门语言。</p> <p>但现在的我稍稍又觉得这样的东西其实还行,只使用类型系统也并没有完全限制 JavaScript 本身的灵活性,并且他帮助我不会犯一些低级错误,而且还能配合 Visual Studio Code 的提示,我觉得这个还是很不错的,最近忙起来的时候,甚至经常把两个输入框的 value 直接进行比较了,于是就想尝试一下 TypeScript。</p> <h2>官方做法</h2> <p>Vue 2.2 以上之后,官方给 Vue已经添加了很多类型声明,那么我们就来实践一下在单文件 Vue 中使用 TypeScript。</p> <p>1. webpack rules 中添加 ts-loader 相关(这里使用 webpack 2)</p> <pre> <code class="language-javascript">{ test: /\.ts$/, exclude: /node_modules|vue\/src/, loader: 'ts-loader', options: { appendTsSuffixTo: [/\.vue$/] } }</code></pre> <p>表示对 .ts 文件编译时使用 ts-loader 进行读取,appendTsSuffixTo 是为了让 tsc 对 vue 文件能够当成一个 module 进行处理,以解决 moudle not found 的问题(tsc 本身不认识 vue 结尾的文件)</p> <p>2. 添加 .d.ts文件</p> <pre> <code class="language-javascript">declare module "*.vue" { import Vue from 'vue' export default Vue }</code></pre> <p>也是为了让 vscode 在 ts 文件中识别 vue 结尾文件</p> <p>3. 项目根目录下添加 tsconfig.json</p> <pre> <code class="language-javascript">{ "compilerOptions": { "allowSyntheticDefaultImports": true, "lib": [ "dom", "es5", "es2015.promise" ], "module": "es2015", "moduleResolution": "node", "isolatedModules": false, "target": "es5" }, "include": [ "./src/**/*.ts" ] }</code></pre> <p>allowSyntheticDefaultImports 是为了能够用 es6 形式的 import,其他就参照 Vue 官网的弄了个最小化的 json。</p> <p>4. 万事俱备,让我们 npm run dev 跑起来!</p> <p>在这里,我们假设使用 Vue 官方的 webpack boilerplate,对 Hello.vue 进行一下改造。</p> <p>在模板的 msg 下新增一行</p> <pre> <code class="language-javascript"><h2>Say Hello Times: {{ count }}</h2></code></pre> <p>并将 script 部分修改成</p> <pre> <code class="language-javascript"><script lang="ts"> import Vue, { ComponentOptions } from 'vue' // Declare the component's type interface HelloInterface extends Vue { msg: string, count: number, sayHello(): number } export { HelloInterface as interface } export default { data() { return { msg: 'Welcome to Your Vue.js App', count: 0 } }, methods: { sayHello() { this.count++; return this.count; } } // We need to explicitly annotate the exported options object // with the Hello type } as ComponentOptions<HelloInterface>; </script></code></pre> <p>这段代码没有什么太大的问题</p> <p>接着我们改造一下 App.vue</p> <pre> <code class="language-javascript"><img src="./assets/logo.png" @click="sayHello"></code></pre> <p> </p> <pre> <code class="language-javascript"><script lang="ts"> import Vue, { ComponentOptions } from 'vue'; import { interface as helloInterface, default as Hello } from './components/Hello.vue'; interface App extends Vue { $refs: { // 对 helloComponent 进行声明,可以使用 helloComponent 上的方法和属性 helloComponent: helloInterface } } export default { methods: { sayHello() { this.$refs.helloComponent.count++; this.$refs.helloComponent.sayHello(); } }, components: { Hello } } as ComponentOptions<App>; </script></code></pre> <p>也就是说,像 refs 这种动态的在运行时才能确定的东西,如果需要在 coding 过程中静态化,则需要在 interface 中对其进行声明,写的 code 稍微有点多,不过可以接受。</p> <ul> <li>注: App.vue 修改成 lang=ts 后,顶层的 main.js 需要换成 main.ts 并修改 webpack 入口点,否则发生 file not found 错误</li> </ul> <h2>vue-class-component</h2> <p>官方的另一种推荐做法是 vue-class-component,不过 demo 和 readme 有点小问题,可把我这个 TypeScript 新手给难到啦,提了 pr 希望快快通过。</p> <p>让我们看看使用 vue-class-component 之后的 Hello.vue</p> <pre> <code class="language-javascript"><script lang="ts"> import Vue from 'vue' import Component from 'vue-class-component' @Component export default class Hello extends Vue { msg: string = 'Welcome to Your Vue.js App' count: number = 0 sayHello(): number { this.count++; return this.count; } } </script></code></pre> <p>再让我们看看 App.vue</p> <pre> <code class="language-javascript"><script lang="ts"> import Vue from 'vue' import Component from 'vue-class-component' import Hello from './components/Hello.vue'; @Component({ components: { Hello } }) export default class App extends Vue { $refs: { helloComponent: Hello } sayHello() { this.$refs.helloComponent.count++; this.$refs.helloComponent.sayHello(); } } </script></code></pre> <p>非常 Cool,非常精炼,暂时没有想到可能会发生的没法解决的因为 vue 或者 vue 组件 和 TypeScript 水土不服的编译错误,而且都有了类型和提示。</p> <h2>总结</h2> <p>尤大佬说在接下来的 Vue 2.5 还会加强一系列的 TypeScript 支持( <a href="/misc/goto?guid=4959755025615445196" rel="nofollow,noindex"> 链接 </a> ),不知道是怎样的支持呢。</p> <p>另外,欢迎大家在评论区发表 Vue + TypeScript 的使用场景以及你遇到的错误。</p> <p> </p> <p>来自:https://zhuanlan.zhihu.com/p/29971290</p> <p> </p>