Использование TypeScript с Vue

TypeScript Vue.js Vuex

Давным-давно, если вы хотели использовать TypeScript в Vue для улучшения опыта разработки, не нужно было много говорить о преимуществах TypeScript. Я проверил много информации и узнал об опыте использования TypeScript во Vue в то время. Поскольку в то время TypeScript не поддерживал Vue в достаточной степени, чтобы вывести «это» в экземпляре vue, эта идея была отложена. После выпуска Vue2.5 и TypeScript2.4,Расширенная поддержка TypeScript для Vue, проблема «этого» была решена, и я, наконец, могу счастливо использовать TypeScript в Vue.

Если вы хотите использовать TypeScript с React, вы можете использоватьинструмент для формирования шаблонов create-react-app-typescript, который по умолчанию создает приложение React на основе TypeScript, и опыт разработки также великолепен. В отличие от React, официальный инструмент создания шаблонов Vue-cli по умолчанию не поддерживает TypeScript.Для получения дополнительной информации вы можете взглянуть на этопроблема.

Так как Vue-cli не предоставляет поддержку по умолчанию, мы настроим его сами.Я считаю, что для квалифицированного фронтенда настройка среды разработки является необходимым навыком... На самом деле, в Интернете есть много соответствующих руководств по настройке, затем просто кратко пройдитесь по нему.

1 Инициализируйте проект vue-cli, установите typescript, ts-loader, tslint, tslint-loader, tslint-config-standard, vue-property-decorator.Выше требуются только typescript и ts-loader, а остальные пакеты используется для улучшения опыта разработки.

2 Добавляем tsconfig.json, вот моя конфигурация (стоит заметить, что рекомендуется включать строгий режим, то есть следующий strit верен, чтобы свойство во Vue можно было строго выводить):

{
  "include": [
    "./src/**/*"
  ],
  "exclude": [
    "node_modules"
  ],
  "compilerOptions": {
    "allowSyntheticDefaultImports": true,
    "experimentalDecorators": true,
    "strict": true,
    "allowJs": true,
    "module": "es2015",
    "target": "es5",
    "moduleResolution": "node",
    "isolatedModules": true,
    "lib": [
      "dom",
      "es5",
      "es2015.promise"
    ],
    "sourceMap": true,
    "pretty": true
  }
}

2 В webpack.base.conf.js необходимо настроить поддержку ts и tsx (закомментированные места новые или нуждаются в доработке):

   resolve: {
    extensions: ['.js', '.vue', '.json', 'ts', 'tsx'], // 新增了'ts', 'tsx'
    alias: {
      'vue$': 'vue/dist/vue.esm.js',
      '@': resolve('src'),
    }
  },
  module: {
    rules: [
      {
        test: /\.ts$/,  // 用于加载项目中的ts文件
        exclude: /node_modules/,
        enforce: 'pre',
        loader: 'tslint-loader'
      },
      {
        test: /\.tsx?$/, // 用于加载项目中的tsx文件
        loader: 'ts-loader',
        exclude: /node_modules/,
        options: {
          appendTsSuffixTo: [/\.vue$/],
        }
      }]

3 Переименуйте main.js в main.ts и измените имя пути в webpack.base.conf.js.

 entry: {
    app: './src/main.ts'
  }

4 Добавьте vue-shim.d.ts в каталог src и добавьте объявление для Vue:

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

После описанной выше настройки базовая среда разработки готова, после чего можно приступать к написанию кода. Чтобы улучшить опыт разработки, мы используемvue-property-decoratorОсновная особенность этого пакета заключается в том, что он инкапсулирует официальный пакет vue-class-component, предоставляет 7 декораторов и создает экземпляры, наследуя Vue, что примерно выглядит следующим образом:

<script lang="ts">
  import {Vue, Component, Prop, Emit, Watch} from 'vue-property-decorator';
  import CommonModal from './CommonModal.vue';

  @Component({
    components: {
      Foo
    }
  })
  export default class HelloWorld extends Vue{

    @Prop({
      type: String,
      required: true
    })
    childProp: string|number;

    tasks: Array<number|string> = [];

    task: string|number = '';

    addTask() {
      this.tasks.push(this.task);
      this.task = '';
    }

    @Watch('task')
    onTaskChange(oldValue: string|number, newValue: string|number) {
      console.log(`oldValue ${oldValue}`);
      console.log(`newValue ${newValue}`);
    }

    @Emit('handleClick')
    // 函数的参数值即是emit的payload
    emitTasks(tasks: Array<string|number>) {
      this.tasks[0] = 'haha';
    }
  }
</script>

Из приведенного выше примера мы можем примерно увидеть новый метод разработки. Здесь следует отметить, что в сценарий необходимо добавить lang='ts'. Поскольку используется vue-property-decorator, запись свойств в экземплярах vue немного отличается от того, что было раньше. Во-первых, нужно включить компонент, на который нужно сослаться, в параметр декоратора Component; во-вторых, при использовании emit параметр, передаваемый родительским компонентом, является параметром функции, как и в задачах выше; переданное свойство от родительского компонента к дочернему компоненту, вам нужно использовать декоратор Prop для объявления и так далее.

Хотя TypeScript в настоящее время лучше поддерживает Vue, инструмент управления состоянием Vuex во Vue не идеален, поэтому мы можем использоватьvuex-classЭтот трехсторонний инструментарий для повышения. Он предоставляет несколько декораторов, таких как State, Getter, Action, Mutation и name-espace.Подробности см. в его официальном примере.Код выглядит следующим образом:

import Vue from 'vue'
import Component from 'vue-class-component'
import {
  State,
  Getter,
  Action,
  Mutation,
  namespace
} from 'vuex-class'

const ModuleGetter = namespace('path/to/module', Getter)

@Component
export class MyComp extends Vue {
  @State('foo') stateFoo
  @State(state => state.bar) stateBar
  @Getter('foo') getterFoo
  @Action('foo') actionFoo
  @Mutation('foo') mutationFoo
  @ModuleGetter('foo') moduleGetterFoo

  // If the argument is omitted, use the property name
  // for each state/getter/action/mutation type
  @State foo
  @Getter bar
  @Action baz
  @Mutation qux

  created () {
    this.stateFoo // -> store.state.foo
    this.stateBar // -> store.state.bar
    this.getterFoo // -> store.getters.foo
    this.actionFoo({ value: true }) // -> store.dispatch('foo', { value: true })
    this.mutationFoo({ value: true }) // -> store.commit('foo', { value: true })
    this.moduleGetterFoo // -> store.getters['path/to/module/foo']
  }
}

С благословением класса Vuex Vue значительно улучшил управление состоянием. Далее будет кратко рассказано, как управлять состоянием после использования TypeScript.

Мой подход заключается в создании интерфейса TypeScript для каждого внутреннего API-интерфейса, а затем определения состояния в Vuex через этот интерфейс, например:

// stateType.js
export interface USERINFO {
  userId: number;
  userName: string;
  avatar: string
}

export default interface STATE {
  userInfo: USERINFO;
}

// state.js
import STATE from './stateType.js';

const state: STATE = {
  userInfo: {
    userId: 0,
    userName: '',
    avatar: '',
  }
};

export default state;

Преимущество этого в том, что интерфейс используется для проверки того, соответствует ли структура данных, возвращаемая фоном, требованиям, и в то же время могут быть сделаны определенные ограничения, когда фронтенд использует данные для рендеринга страниц. Когда вам нужно провести рефакторинг, вам нужно только изменить интерфейс, соответствующий состоянию, и тогда вы можете пройти весь путь гладко, что очень круто.

В настоящее время официально запущен проект Vue, рефакторинг которого выполнен с использованием TypeScript, и его ремонтопригодность значительно улучшилась.

Справочные ресурсы:

kaorun343/vue-property-decorator
ktsn/vuex-class
Подробное руководство по вводу в Vue2.5+ Typescript — Vuex