Vue.js 2 Design Patterns and Best Practices
上QQ阅读APP看书,第一时间看更新

TypeScript and Vue

You may have used TypeScript in the past, or you may be curious about how you can take advantage of the extra tooling TypeScript provides inside of your Vue projects. Why use TypeScript? A recent study by Gao et al found that TypeScript/static typing tools reduced committed bugs by 15% (https://goo.gl/XUTPf4).

If you've used Angular before, this syntax should make you feel right at home, as we'll be using decorators and ES2015 classes. Let's investigate how we can add TypeScript to a project built with the Vue CLI:

# Create a new Vue project
vue init webpack-simple typescript-vue

# Change directory
cd typescript-vue

# Install dependencies
npm install

You should get the following output on the Terminal:

If we navigate to our project directory and run npm install as per the instructions, we then need to install the TypeScript loader and edit our Webpack configuration. This allows us to load .ts files inside of the project, and because we've used the webpack-simple template, it's as simple as installing the loader and making a few changes. At the same time, we can also install TypeScript to the project:

# Install TypeScript and the TypeScript Loader
npm install typescript ts-loader --save-dev

We then need to make some changes to our Webpack configuration to add our new loader. Hot Module Replacement is enabled by default, so there is no need to refresh to see any changes once loaded.

Remember to run the project from the command line, and type npm dev.

We need to change our entry point to be main.ts (and subsequently rename it), as well as define the ts-loader and remove the babel-loader in order to do it, and edit the webpack.config.js file, pasting the following contents:

var path = require('path');
var webpack = require('webpack');

module.exports = {
entry: './src/main.ts',
output: {
path: path.resolve(__dirname, './dist'),
publicPath: '/dist/',
filename: 'build.js'
},
module: {
rules: [
{
test: /\.vue$/,
loader: 'vue-loader',
options: {
loaders: {}
}
},
{
test: /\.tsx?$/,
loader: 'ts-loader',
exclude: /node_modules/,
options: {
appendTsSuffixTo: [/\.vue$/]
}
},
{
test: /\.(png|jpg|gif|svg)$/,
loader: 'file-loader',
options: {
name: '[name].[ext]?[hash]'
}
}
]
},
resolve: {
extensions: ['.ts', '.js', '.vue'],
alias: {
vue$: 'vue/dist/vue.esm.js'
}
},
devServer: {
historyApiFallback: true,
noInfo: true
},
performance: {
hints: false
},
devtool: '#eval-source-map'
};

if (process.env.NODE_ENV === 'production') {
module.exports.devtool = '#source-map';
// http://vue-loader.vuejs.org/en/workflow/production.html
module.exports.plugins = (module.exports.plugins || []).concat([
new webpack.DefinePlugin({
'process.env': {
NODE_ENV: '"production"'
}
}),
new webpack.optimize.UglifyJsPlugin({
sourceMap: true,
compress: {
warnings: false
}
}),
new webpack.LoaderOptionsPlugin({
minimize: true
})
]);
}

After this, we can create a tsconfig.json inside of our project root, which is responsible for appropriately configuring our TypeScript setup:

{
"compilerOptions": {
"lib": ["dom", "es5", "es2015"],
"module": "es2015",
"target": "es5",
"moduleResolution": "node",
"experimentalDecorators": true,
"sourceMap": true,
"allowSyntheticDefaultImports": true,
"strict": true,
"noImplicitReturns": true
},
"include": ["./src/**/*"]
}

TypeScript is now set up in our project, but to truly take advantage of this within our Vue applications we should also use vue-class-component. This allows us to take advantage of static typing on our component properties, as well as define components as native JavaScript classes:

# Install TypeScript helpers
npm install vue-class-component --save-dev

We can then define our App.vue file by first specifying it as a script with the lang="ts" attribute. We can then import Vue as always, but as well as this, we're also importing Component from vue-class-component to be used as a decorator within this file. This allows us to specify this as a new Vue component, and using the Component decorator we can define properties, templates, and more.

Inside of our Component decorator, we're specifying a template with an input box and button. This example allows us to see how we can bind to class properties, as well as call methods from our class. The following code should replace the code already in the App.vue file:

<script lang="ts">
import Vue from 'vue';
import Component from 'vue-class-component';

@Component({
template: `
<div>
<input type="text" v-model="name" />
<button @click="sayHello(name)">Say Hello!</button>
</div>
`
})
export default class App extends Vue {
name: string = 'Paul';

sayHello(name: string): void {
alert(`Hello ${name}`)
}
}
</script>

After running the preceding code, you should get something like this: