1
votes

I am writing a Nuxt application in TypeScript. I have encountered a problem when trying to access $i18n object on Nuxt. I am getting a warning in VS Code saying:

Property '$i18n' does not exist on type 'MyClass'.

My script part in the component code is like the following:

<script lang="ts">
  import { Vue, Component, Prop } from 'vue-property-decorator'
  import ILocale from '~/types/vue/Locales'

  @Component
  export default class MyClass extends Vue {
    @Prop({ type: Boolean, default: true }) showLanguageSwitch!: boolean

    get availableLocales(): ILocale[] {
      return this.$i18n.locales.filter((l) => l.code !== this.$i18n.locale)
    }
  }
</script>

I have a shim file in the root of the project:

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

Is it the place where I should extend the interface? How do I actually do it as Vue is not TS interface but a class definition with its own type.

The only thing that worked so far was adding a private property explicitly on MyClass but then it complains about lack of initialisation and it feels wrong anyway. All other common properties of Vue are recognised byt TS, like $fetch, $config etc.

TS config:

{
  "compilerOptions": {
    "target": "ES2018",
    "module": "ESNext",
    "moduleResolution": "Node",
    "lib": [
      "ESNext",
      "ESNext.AsyncIterable",
      "DOM"
    ],
    "esModuleInterop": true,
    "allowJs": true,
    "sourceMap": true,
    "strict": true,
    "noEmit": true,
    "experimentalDecorators": true,
    "baseUrl": ".",
    "paths": {
      "~/*": [
        "./*"
      ],
      "@/*": [
        "./*"
      ]
    },
    "types": [
      "@types/node",
      "@nuxt/types"
    ]
  },
  "exclude": [
    "node_modules"
  ]
}

Nuxt config:

export default {
  head: {
    htmlAttrs: {
      lang: 'en',
    },
    meta: [
      { charset: 'utf-8' },
      { name: 'viewport', content: 'width=device-width, initial-scale=1' },
      { hid: 'description', name: 'description', content: '' },
    ],
    link: [{ rel: 'icon', type: 'image/x-icon', href: '/favicon.ico' }],
  },
  publicRuntimeConfig: {},
  css: [
    '~assets/scss/fonts.scss',
    '~assets/scss/variables.scss',
    '~assets/scss/mixins.scss',
    '~assets/scss/reset.scss',
    '~assets/scss/typography.scss',
  ],
  i18n: {
    lazy: true,
    langDir: 'i18n/',
    locales: [
      {
        code: 'en',
        iso: 'en',
        file: 'en.json',
        name: 'English',
      },
      {
        code: 'de-DE',
        iso: 'de-DE',
        file: 'de.json',
        name: 'Deutsch',
      },
    ],
    defaultLocale: 'en',
    vueI18n: {
      fallbackLocale: 'en',
    },
    seo: true,
    strategy: 'prefix_except_default',
  },
  plugins: ['~/plugins/jsonld', '~/plugins/helpers'],
  components: true,
  buildModules: ['@nuxtjs/eslint-module', '@nuxt/typescript-build'],
  modules: [
    '@nuxtjs/axios',
    '@nuxtjs/style-resources',
    'nuxt-i18n',
    '@nuxtjs/sitemap',
  ],
  axios: {},
  server: {
    port: 3000,
    host: '0.0.0.0',
  },
  router: {
    middleware: ['langRedirect', 'seoMiddleware'],
    trailingSlash: true,
  },
  serverMiddleware: [
    '~/server-middleware/redirectApex.js',
    { path: '/api', handler: '~/server-middleware/rest.js' },
  ],
  build: {},
  styleResources: {
    scss: [
      '~assets/scss/fonts.scss',
      '~assets/scss/variables.scss',
      '~assets/scss/mixins.scss',
      '~assets/scss/reset.scss',
      '~assets/scss/typography.scss',
    ],
  },
}

(EDIT) Correct function now after loading the nuxt-18n types:

get availableLocales(): NuxtVueI18n.Options.LocaleObject[] {
  if (!this.$i18n.locales) {
    return []
  }

  return (this.$i18n.locales as NuxtVueI18n.Options.LocaleObject[]).filter(
    (l) => l.code !== this.$i18n.locale
  )
}
1

1 Answers

2
votes

In tsconfig.json add "nuxt-i18n" to types entry :

    "types": [
      "@types/node",
      "@nuxt/types",
       "nuxt-i18n"
    ]