You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Vue-i18n结合TypeScript使用数组时遇类型错误求助

解决Vue-i18n数组元素类型推断为never的TypeScript错误

问题分析

你遇到的Property 'code' does not exist on type 'never'错误,是因为TypeScript无法从JSON文件中正确推断出国家数组元素的具体类型。虽然已将MessageSchema基于enUS定义,但Vue-i18n的类型系统对数组的推断存在局限性,导致数组元素被缩小为never类型。

解决方案

方案1:显式扩展MessageSchema类型

在/boot/i18n.ts中,手动定义国家对象类型并扩展原有MessageSchema,明确数组的类型结构:

import enUS from 'src/i18n/en-US.json'
import nlBE from 'src/i18n/nl-BE.json'

// 定义国家对象的具体类型
type Country = {
  code: string
  name: string
}

// 扩展MessageSchema,覆盖countries字段的类型
type MessageSchema = Omit<typeof enUS, 'page'> & {
  page: Omit<typeof enUS['page'], 'landing'> & {
    landing: Omit<typeof enUS['page']['landing'], 'countries'> & {
      countries: Country[]
    }
  }
}

export default boot(({ app }) => {
  const i18n = createI18n<[MessageSchema], 'en-US' | 'nl-BE'>({
    legacy: false,
    locale: Quasar.lang.getLocale(),
    fallbackLocale: 'en-US',
    // 断言消息结构符合MessageSchema
    messages: { 'en-US': enUS as MessageSchema, 'nl-BE': nlBE as MessageSchema },
  })

  app.use(i18n)
})

方案2:添加JSON类型声明文件

创建src/i18n/index.d.ts,统一约束所有语言JSON文件的类型:

declare module '*.json' {
  export interface Country {
    code: string
    name: string
  }

  export interface MessageSchema {
    page: {
      landing: {
        title: {
          selectCountry: string
        }
        countries: Country[]
      }
    }
    // 补充其他语言字段的类型定义
  }

  const value: MessageSchema
  export default value
}

随后在/boot/i18n.ts中导入该类型:

import enUS from 'src/i18n/en-US.json'
import nlBE from 'src/i18n/nl-BE.json'
import type { MessageSchema } from 'src/i18n'

export default boot(({ app }) => {
  const i18n = createI18n<[MessageSchema], 'en-US' | 'nl-BE'>({
    legacy: false,
    locale: Quasar.lang.getLocale(),
    fallbackLocale: 'en-US',
    messages: { 'en-US': enUS, 'nl-BE': nlBE },
  })

  app.use(i18n)
})

方案3:组件内局部类型断言

如果不想修改全局类型,可在LandingPage.vue中对$tm的返回值做类型断言:

<template>
  <q-page>
    <div>
      <q-card v-for="country in countries" :key="country.code">
        <q-card-section>
          <div> {{ $rt(country.name) }} </div>
        </q-card-section>
      </q-card>
    </div>
  </q-page>
</template>

<script setup lang="ts">
interface Country {
  code: string
  name: string
}

// 显式指定数组元素类型
const countries = $tm('page.landing.countries') as Country[]
</script>

原理说明

TypeScript对JSON文件的类型推断依赖静态分析,当数组元素类型无法被明确识别时(比如多语言文件存在潜在结构差异),会将元素类型缩小为never。通过显式定义类型,给TypeScript提供明确的类型上下文,即可解决属性不存在的错误。

内容的提问来源于stack exchange,提问作者DarkLite1

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.17 08:23:12