Types VUEX store

Goal 1

Бачити автокомпліт стора, а не бред від IDE

Оголошуємо свій Store

import { Store } from 'vuex'
import { iStoreState, iThread } from './types'

declare module 'vue/types/vue' {
    interface Vue {
        $store: Store<iStoreState> & {
            state: iStoreState
            getters: {
                isAuthenticated: boolean
                activeThread: iThread | undefined
            }
        }
    }
}

видалити $store: Store<any> з node_modules/vuex/types/vue.d.ts

Результат

Goal 2

Було б круто коли $store.commit перевіряв вхідні параметри

Оголошуємо типи для Store

// file path: types/Store.ts
import { iSearchUser } from 'social-api'
import { iFemaleSimple, iProfile, iDictionary, iUser } from '@/types'

export type MutationTypes = {
    COMMON_ADD_DICTIONARY: iDictionary
    COMMON_ADD_FEMALES: iFemaleSimple[]
    COMMON_INIT_USER: iUser
    COMMON_CLEAR: never
    COMMON_FEMALE_ONLINE: { ids: number[], status: boolean }
    COMMON_TOGGLE_SITE_BAR: boolean
    PROFILE_ADD: (iProfile | iSearchUser)[]
    PROFILE_CREATE_DEFAULT: number
}

Типізуємо commit

import { Store, CommitOptions } from 'vuex'
import { iStoreState, iThread, MutationTypes } from './types'

declare module 'vue/types/vue' {
    interface Vue {
        $store: Store<iStoreState> & {
            state: iStoreState
            getters: {
                isAuthenticated: boolean
                activeThread: iThread | undefined
            }
            commit<key extends keyof MutationTypes>(
                type: key,
                payload?: MutationTypes[key],
                options?: CommitOptions,
            ): void
        }
    }
}

Ніфіга не працює

// file node_modules/types/index.ts

export interface Dispatch {
  (type: string, payload?: any, options?: DispatchOptions): Promise<any>;
  <P extends Payload>(payloadWithType: P, options?: DispatchOptions): Promise<any>;
}

export interface Commit {
  (type: string, payload?: any, options?: CommitOptions): void;
  <P extends Payload>(payloadWithType: P, options?: CommitOptions): void;
}

Той момент коли наявна типізація шкідлива, потрібно видаляти

Result

Але без аргументів не має помилки, а він в даному випадку обов'язковий

В компонентах порядок, але...

Додаємо типи до видаленого інтерфейса

// file: shims.d.ts

declare module 'vuex/types/index' {
    interface Commit {
        <T extends keyof Store.MutationTypes>(
            name: T,
            payload: Store.MutationTypes[T],
            options?: CommitOptions,
        ): void
    }
}

А як же об'єктна нотація?

this.$store.commit({
  type: 'COMMON_FEMALE_ONLINE',
  ids: this.id,
  status: 'error',
})

Автоматизація видалення поганих типів

const fs = require('fs')

const pathVuex = './node_modules/vuex/types/index.d.ts'
const pathVue = './node_modules/vuex/types/vue.d.ts'

function exitIfErr(err) {
    if (err) {
        process.exit(1)
    }
}

fs.readFile(pathVuex, 'utf8', (err, data) => {
    exitIfErr(err)

    const res = data
        .replace(/(\(type: string, payload\?: any, options\?)/g, '// $1')
        .replace(/(<P extends Payload>\(payloadWithType: P)/g, '// $1')

    fs.writeFile(pathVuex, res, exitIfErr)
})

fs.readFile(pathVue, 'utf8', (err, data) => {
    exitIfErr(err)

    const res = data.replace(/(\$store: Store<any>;)/g, '// $1')

    fs.writeFile(pathVue, res, exitIfErr)
})

Vuex types legacy code

By Kolya Koval

Vuex types legacy code

  • 213