自主搭建vue 2 + typescript 3.7 + eslint 6.0, 及起飞姿势. 附脚手架源码typescript-vue-eslint-starter

目录

  • 脚手架搭建

  • d.ts文件声明

  • vue-property-decorator 装饰器使用

  • vuex-class 装饰器使用

  • typescript按需转换ES6 Api

webpack 完整配置可以参考 typescript-vue-eslint-starter [ https://github.com/vok123/typescript-vue-eslint-starter ]

欢迎提建议,如果觉得有用的给个star哈~

↓↓↓↓↓↓高能时刻↓↓↓↓↓↓

开局一只蔡徐坤, 涨薪全靠vue + ts [https://www.bilibili.com/video/av50374517/?spm_id_from=333.788.videocard.4]

脚手架搭建

1. 安装依赖

  • 开发依赖

npm i -D @typescript-eslint/eslint-plugin @typescript-eslint/experimental-utils @typescript-eslint/parser @typescript-eslint/typescript-estree eslint eslint-config-standard eslint-plugin-standard eslint-plugin-import eslint-plugin-promise eslint-loader eslint-plugin-node eslint-plugin-vue typescript ts-loader

  • 项目依赖

npm i -S vue-class-component vue-property-decorator vuex-class

2. Webpack loader配置 (ts-loader/eslint-loader)

完整webpack配置 [https://github.com/vok123/typescript-vue-eslint-starter/blob/master/build/webpack.config.js]

module: {
  rules: [
    {
      test: /\.ts(x)?$/,
      loader: 'ts-loader',
      exclude: /node_modules/,
      options: {
        appendTsSuffixTo: [/\.vue$/],
        transpileOnly: true,
        happyPackMode: false
      }
    },
    {
      test: /\.(js|vue|ts|tsx|jsx)$/,
      enforce: 'pre',
      exclude: /node_modules/,
      loader: 'eslint-loader',
      options: {
        fix: false,
        extensions: ['.js', '.jsx', '.vue', '.ts', '.tsx'],
        cache: false,
        emitWarning: true,
        emitError: false
      }
    }
  ];
}

3. 根目录添加eslint配置文件 .eslintrc.js



module.exports = {
  plugins: ['vue', '@typescript-eslint'],
  parserOptions: {
    parser: '@typescript-eslint/parser',
    env: { es6: true },
    sourceType: 'module'
  },
  root: true,
  env: {
    browser: true,
    node: true,
    serviceworker: true
  },
  extends: ['plugin:vue/base', 'plugin:@typescript-eslint/recommended', 'plugin:vue/essential', 'standard'],
  rules: {
    // 设置默认eslint规则
    'one-var': 0,
    'arrow-parens': 0,
    'generator-star-spacing': 0,
    'no-debugger': 0,
    'no-console': 0,
    semi: [2, 'always'],
    'no-extra-semi': 2,
    'space-before-function-paren': 0,
    eqeqeq: 0,
    'spaced-comment': 0,
    'no-useless-escape': 0,
    'no-tabs': 0,
    'no-mixed-spaces-and-tabs': 0,
    'new-cap': 0,
    camelcase: 0,
    'no-new': 0,
    indent: 'off',
    semi: 'off',
    // 设置typescript-eslint规则
    // https://github.com/typescript-eslint/typescript-eslint/tree/master/packages/eslint-plugin/docs/rules
    '@typescript-eslint/semi': ['error'],
    '@typescript-eslint/indent': ['error', 2],
    '@typescript-eslint/explicit-function-return-type': 0
  }
};

4. 根目录添加 tsconfig.json


{
  "compilerOptions": {
    "target": "es5",
    "module": "esnext",
    "strict": true,
    "jsx": "preserve",
    "importHelpers": true,
    "moduleResolution": "node",
    "experimentalDecorators": true,
    "esModuleInterop": true,
    "allowSyntheticDefaultImports": true,
    "sourceMap": true,
    "allowJs": true,
    "baseUrl": ".",
    "types": ["webpack-env", "node"],
    "paths": {
      "@/*": ["src/*"]
    },
    "lib": ["esnext", "dom", "dom.iterable", "scripthost"]
  },
  "include": [
    "src/**/*.ts",
    "src/**/*.tsx",
    "src/**/*.vue",
    "tests/**/*.ts",
    "tests/**/*.tsx"
  ],
  "exclude": ["node_modules"]
}

d.ts文件声明

src/@types/shims-vue.d.ts

  • 声明.vue文件

declare module '*.vue' {
  import Vue from 'vue'
  export default Vue
}

  • 声明组件实例属性或者方法 ( 类似 this.$route ) 来源[https://github.com/vuejs/vue-router/blob/dev/types/vue.d.ts]
declare module "vue/types/vue" {
  interface Vue {
    $message: (msg: string): void;
    $balala: string;
  }
}
// 在组件中使用
this.$balala
this.$message('Hello world');
  • 声明new Vue自定义属性或者方法 (类似 new Vue({ router: router })) 来源[https://github.com/vuejs/vue-router/blob/dev/types/vue.d.ts]

declare module "vue/types/options" {
  interface ComponentOptions {
    i18n: any
  }
}

// 使用
new Vue({
  i18n, ...
});

  • 声明第三方npm包
// 声明 element-ui
declare module 'element-ui'

// 声明 axios
declare module 'axios' {
  import Axios from 'axios/index';
  export default Axios;
}

vue-property-decorator 装饰器使用

  • 常用装饰器及方法
装饰器 用途 描述
Component 声明class组件 只要是个组件都必须加该装饰器
Prop 声明props 对应普通组件声明中的props属性
Watch 声明监听器 对应普通组件声明中的watch属性
Mixins 混入继承 对应普通组件声明中的mixins属性
Emit 子组件向父组件值传递 对应普通this.$emit()
Inject 接收祖先组件传递的值 对应普通组件声明中的inject属性
Provide 祖先组件向其所有子孙后代注入一个依赖 对应普通组件声明中的provide属性
  • 用法

    • vue 钩子写法
    // javascript
    
    
    // --------typescript--------
    
    
    
    • Component
    
    // javascript
    
    import helloWorld from './helloWorld.vue';
    export default {
      components: {
        helloWorld
      }
    }
    
    // --------typescript--------
    
    import helloWorld from './helloWorld.vue';
    import { Component, Vue } from 'vue-property-decorator';
    
    @Component({
      components: {
        helloWorld
      }
    })
    export default class App extends Vue {}
    
    
    • Prop
    // javascript
    export default {
      props: {
        msg: {
          type: String,
          default: 'Hello world',
          required: true,
          validator: (val) => (val.length > 2)
        }
      }
    }
    
    
    // --------typescript--------
    
    import { Component, Vue, Prop } from 'vue-property-decorator';
    
    @Component
    export default class HelloWorld extends Vue {
      @Prop({
        type: String,
        default: 'Hello world',
        required: true,
        validator: (val) => (val.length > 2)
      }) msg!: string
    }
    
    
    • Watch
    // javascript
    
    export default {
      data() {
        return {
          value: ''
        };
      },
      watch: {
        value: {
          handler() {
            console.log(this.value);
          },
          deep: true,
          immediate: true
        }
      }
    }
    
    // --------typescript--------
    
    import { Component, Vue, Watch } from 'vue-property-decorator';
    
    @Component
    export default class App extends Vue {
      value: string = ''
      @Watch('value', { deep: true, immediate: true })
      valueWatch() {
        console.log(this.value);
      }
    }
    
    
    • Mixins
    // javascript
    
    // -info.js
    export default {
      methods: {
        mixinsShow() {
          console.log('徐蔡坤');
        }
      }
    }
    
    // -hello-world.vue
    import mixinsInfo from './info.js';
    export default {
      mixins: [mixinsInfo],
      mounted() {
        this.mixinsShow(); // 徐蔡坤
      }
    }
    
    // --------typescript--------
    // -info.ts
    import { Component, Vue } from 'vue-property-decorator';
    
    @Component
    export default class MixinsInfo extends Vue {
        mixinsShow() {
          console.log('徐蔡坤');
        }
    }
    
    // -hello-world.vue
    import { Component, Vue, Mixins } from 'vue-property-decorator';
    import mixinsInfo from './info.ts';
    
    @Component
    export default class HelloWorld extends Mixins(mixinsInfo) {
      mounted() {
        this.mixinsShow(); // 徐蔡坤
      }
    }
    
    
    • Emit
    // javascript
    
    // -children.vue
    
    
    // -parent.vue
    
    
    
    
    // --------typescript--------
    // -children.vue
    
    
    
    
    // -parent.vue
    
    
    
    
    
    • Provide/Inject
    // javascript
    
    // -children.vue
    
    
    // -parent.vue
    
    
    
    
    
    // --------typescript--------
    
    // -children.vue
    
    
    
    // -parent.vue
    
    
    
    
    
    
    • 计算属性
    // javascript
    
    export default {
      data() {
        return {
          hobby: '唱, 跳, rap, 篮球'
        };
      },
      computed: {
        msg() {
          return '我也会' + this.hobby;
        }
      },
      mounted() {
        console.log(this.msg); // 我也会唱, 跳, rap, 篮球
      }
    }
    
    // --------typescript--------
    
    // -hello-world.vue
    import { Component, Vue } from 'vue-property-decorator';
    
    @Component
    export default class HelloWorld extends Vue {
      hobby: string = '唱, 跳, rap, 篮球'
      get msg() {
        return '我也会' + this.hobby;
      }
      mounted() {
        console.log(this.msg); // 我也会唱, 跳, rap, 篮球
      }
    }
    
    

vuex-class 装饰器使用

装饰器 用途
State 获取vuex state
Getter 获取vuex getter
Mutation 获取vuex mutation
Action 获取vuex actions
  • vuex typescript 基础定义

    // -store/store.ts
    
    import Vue from 'vue';
    import Vuex, { StoreOptions } from 'vuex';
    import user from './modules/user';
    
    Vue.use(Vuex);
    interface RootState {
      version: string;
    }
    const store: StoreOptions = {
      strict: true,
      state: {
        version: '1.0.0'
      },
      modules: {
        user
      }
    };
    
    export default new Vuex.Store(store);
    
    
    
    // -store/modules/user.ts
    
    import { Module } from 'vuex';
    export interface UserInfo {
      uId: string;
      name: string;
      age: number;
    }
    
    interface UserState {
      userInfo: UserInfo;
    }
    
    const user: Module = {
      namespaced: true,
      state: {
        userInfo: {
          uId: '',
          name: '',
          age: 0
        }
      },
      getters: {
        isLogin(state) {
          return !!state.userInfo.uId;
        }
      },
      mutations: {
        updateUserInfo(state, userInfo: UserInfo): void {
          Object.assign(state.userInfo, userInfo);
        }
      },
      actions: {
        async getUserInfo({ commit }): Promise {
          let { userInfo } = await getUserInfo();
          commit('updateUserInfo', userInfo);
        }
      }
    };
    
    export default user;
    
    
    • vuex-class 装饰器
    
    
    
    • 在非vue组件的.ts中获取store数据
    // test.ts
    
    import store from './store/store';
    
    if (store.getters['user/isLogin'] === false) {
      console.log('未登录');
    }
    
    

typescript按需转换ES6 Api

默认情况下typescript在转换语法为es3或者es5时并不会转换ES6 Api, 例如(Object.values, Array.fill ...)
在这种情况下我们可以使用 (ts-polyfill) [https://github.com/ryanelian/ts-polyfill] 定向指定需要转换的api

你可能感兴趣的:(自主搭建vue 2 + typescript 3.7 + eslint 6.0, 及起飞姿势. 附脚手架源码typescript-vue-eslint-starter)