Vue + TypeScript 尝鲜体验

ognm2924 2年前
   <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>