Official TypeScript support has been added to Vue.js 2.x and the old bindings have been changed considerably since this repository has been created. We recommend to start new projects with Vue CLI.
Example project for Vue.js 2.0 and TypeScript 2.0 using
- Browserify/watchify for bundling
- vueify for Vue.js components supporting Hot Module Replacement
- Tsify for TypeScript support in a Browserify environment including source maps
- Pug for wrist-friendly templates
- Jest for unit and snapshot testing
- html2jade for compact HTML snapshots
- TSLint to check TypeScript sources
and illustrating
- vue-typescript-component to use TypeScript classes as Vue.js components
- vue-typescript-import-dts to import
*.vuefiles in TypeScript sources - vue-typescript-jest to test Vue.js components and TypeScript sources using Jest
- vue-jest-utils to simplify snapshot testing of Vue.js components using Jest and html2jade
# once: install dependencies
npm install
# serve with HMR at http://localhost:8080
npm start
# run unit tests in watch mode
npm run test -- --watch
# TSLint
npm run lint
# lint, test, and build for production with minification
npm run dist
# for more, cf. package.jsonExcept index.html, all source code is located in the src directory. The starting point is index.ts which initializes the main Vue instance and adds the top-level app.vue component. counter.ts illustrates the central Vue.js concepts: data, props, computed properties, watches, and events. The same functionality is also split in two parts in parent.ts and child.ts, which show the use of a complex listener interface to communicate from child to parent with compile-time type checking.
The development output is located in the debug directory and npm run dist creates minimized output in the dist directory.
The file test/counter.spec.ts contains an example Jest unit test that checks the HTML rendering after initialization. Furthermore, it contains a snapshot test that utilizes html2jade to generate a compact and readable snapshot of the result after a series of user interactions.
- TypeScript classes as Vue.js components using decorators with vue-typescript-component
import Vue = require('vue')
import * as vts from 'vue-typescript-component'
// http://vuejs.org/guide/components.html
@vts.component()
// extend Vue to get code completion for Vue.js instance functionality
export default class CounterTs extends Vue {
// http://vuejs.org/api/#props
@vts.prop({type: String, required: false})
fromParent: String
// http://vuejs.org/api/#data
name = 'counter'
count = 0
// http://vuejs.org/api/#methods
inc() {
this.count++
}
dec() {
this.count--
}
// http://vuejs.org/api/#computed
get opposite(): number {
return -this.count
}
set opposite(value: number) {
this.count = -value
}
// http://vuejs.org/api/#watch
@vts.watch('count')
watchForSignChange(val: number, oldVal: number) {
if (val === -oldVal) {
this.$emit('signChanged')
}
}
// http://vuejs.org/api/#Options-Lifecycle-Hooks
created(): void {
this.count++
}
}- Import
*.vuefiles in TypeScript classes with vue-typescript-import-dts
// the child component
import * as Child from './child.vue'
@vts.component({components: {Child}})
export default class ParentTs extends Vue implements ChildListener {...}- Use a complex listener interface with compile-time type checks
// child component declares listener interface
export interface ChildListener {
inc(): void
dec(): void
greet(text: String): void
}// parent components imports and implements interface
import { ChildListener } from './child'
export default class ParentTs extends Vue implements ChildListener {...}- Jest unit testing of Vue.js components (JavaScript or TypeScript) with vue-typescript-jest
/// <reference path='../node_modules/@types/jest/index.d.ts' />
import Vue = require('vue')
import * as SUT from '../src/counter.vue'
describe('counter.vue', () => {
it('should initialize correctly', () => {
const vm = new Vue({
el: document.createElement('div'),
render: (h) => h(SUT),
})
expect(vm.$el.querySelector('div span')!.textContent).toBe('counter')
})
})- Simple Jest snapshot testing with vue-jest-utils
// ...
import {expectToMatchSnapshot, clickNthButton} from 'vue-jest-utils'
describe('counter.vue', () => {
it('should just work', () => {
const vm = new Vue({
el: document.createElement('div'),
render: (h) => h(SUT),
})
clickNthButton(vm.$el, 1)
clickNthButton(vm.$el, 3)
clickNthButton(vm.$el, 2)
// return a Promise that
// 1. calls vm.nextTick()
// 2. checks the snapshot of vm.$el using html2jade
return expectToMatchSnapshot(vm)
})
})Inline TypeScript Code in *.vue files is not supported, because external TypeScript code allows IDE support and source maps. Additionally, since the TypeScript compiler does not understand *.vue files, code reuse between components (including, e.g., interface definitions) is impossible with inline code.
This example does not directly use Babel. However, vueify automatically enables Babel for *.vue files if babel-core is present, and babel-core is an indirect dependency of jest. In this case, vueify depends on additional Babel packages, which are, therefore, included as devDependencies. To enable complete support for Babel, e.g. to mix TypeScript and ES2015 sources, run npm i babelify --save-dev and add 'babelify' to the browserify.transform list in package.json.
Contributions including bug reports, tests, and documentation are more than welcome. Cf. above for how to get started with development.
This project has been heavily inspired by the Browserify template of vue-cli (https://github.com/vuejs-templates/browserify).