question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

[typescript] I18n.global incorrect type when in "composition" mode (should be Composer, is VueI18n)

See original GitHub issue

Reporting a bug?

This is a TypeScript-related bug.

From the docs https://vue-i18n.intlify.dev/api/general.html#global it is said that “If the I18n#mode is ‘legacy’, then I18n.global can access to a global VueI18n instance, else then I18n#mode is ‘composition’ , you can access to the global Composer instance.”.

I’ve found this to be true at runtime, but the inferred TypeScript type is always VueI18n even when in “composition” mode. This throws errors at compile time and in the editor when I try to access Composer properties which are differently typed or absent from VueI18n (according to the mapping found at https://vue-i18n.intlify.dev/guide/advanced/composition.html#mapping-between-vuei18n-instance-and-composer-instance). More on that, this breaks typing on functions that return useI18n() | i18n.global.

Expected behavior

The following code should not throw a typescript error on the last line

import { createI18n } from "vue-i18n";

const testI18n = createI18n({
  legacy: false,
  locale: "ja",
  fallbackLocale: "en",
  messages: {
    en: {
      message: {
        hello: "hello world",
      },
    },
    ja: {
      message: {
        hello: "こんにちは、世界",
      },
    },
  },
});

const globalComposerInstance = testI18n.global;
console.log(globalComposerInstance.formatter); // this should be absent in Composer instance!
console.log(globalComposerInstance.getMissingHandler); // this should be present is Composer instance!

Instead it throws the following error:

Property 'getMissingHandler' does not exist on type 'VueI18n<{ en: { message: { hello: string; }; }; ja: { message: { hello: string; }; }; }, {}, {}, string, \"ja\" | \"en\", \"ja\" | \"en\", Composer<{ en: { message: { hello: string; }; }; ja: { message: { hello: string; }; }; }, ... 4 more ..., \"ja\" | \"en\">>'.

Reproduction

Use the above snippet anywhere in a project with vue-i18n@9.2.0-beta.28 and typescript@4.5.4. Hope it is enough, if not i will provide a repro.

System Info

System:
    OS: Linux 5.11 Linux Mint 20.2 (Uma)
    CPU: (12) x64 Intel(R) Core(TM) i7-10710U CPU @ 1.10GHz
    Memory: 843.50 MB / 15.47 GB
    Container: Yes
    Shell: 5.8 - /usr/bin/zsh
  Binaries:
    Node: 14.15.0 - ~/.nvm/versions/node/v14.15.0/bin/node
    Yarn: 1.22.17 - ~/.nvm/versions/node/v14.15.0/bin/yarn
    npm: 8.1.0 - ~/.nvm/versions/node/v14.15.0/bin/npm
  Browsers:
    Brave Browser: 97.1.34.80
    Chrome: 97.0.4692.71
    Firefox: 95.0.1
  npmPackages:
    vue-i18n: ^9.2.0-beta.28 => 9.2.0-beta.28

Screenshot

immagine

Additional context

The actual value of testI18n.global is in fact a Composer instance. The following code:

console.log("testI18n.global", testI18n.global);
console.log("testI18n.global.formatter", testI18n.global.formatter);

logs the following:

immagine

Validations

Issue Analytics

  • State:closed
  • Created 2 years ago
  • Comments:7 (3 by maintainers)

github_iconTop GitHub Comments

1reaction
sullyD64commented, Jan 20, 2022

I understand that. I thought that I18n.global and the returned Composer instance from useI18n() would be the same.

For anyone interested, i’ve found a workaround to my use case by double casting I18n.global as follows:

return i18n.global as unknown as Composer<{ message: typeof messages["en"] }, "en" | "ja">;

Problem is solved for me, but I still think that either the docs or the typings should be fixed to work as advised in https://vue-i18n.intlify.dev/api/general.html#global, so I’m leaving this open.

Quoting myself:

the docs mention the type inference for I18n.global to depend solely on I18n.mode, which is correctly reporting “composition” since i’ve set legacy.false, and don’t mention needing to force the type parameter on createI18n.

Thank you @PeterAlfredLee for your kind patience!

1reaction
PeterAlfredLeecommented, Jan 20, 2022

but I’ve noticed that by casting <false>, the Composer instance doesn’t infer types from the schema

You can pass schema and false at the same time, see also this example. Hope this helps.

Read more comments on GitHub >

github_iconTop Results From Across the Web

TypeScript Support - Vue I18n - Intlify
The following is an example code to define type-safe resources for messages defined with createI18n option. Locale messages resource: { "world": ...
Read more >
Vue.js 3 - Error while using Vue I18n plugin in vue - Cannot ...
You should install vue-i18n@next which is compatible with Vue 3: npm install --save vue-i18n@next. or via using yarn yarn add vue-i18n@next.
Read more >
vuei18n Composer instance type not correctly inferred in ...
vuei18n Composer instance type not correctly inferred in templates when using composition API : WEB-52090.
Read more >
The Ultimate Vue Localization Guide | Phrase
Dive into Vue localization and learn how to plug the Vue I18n library into your app, so you can make it accessible to...
Read more >
@intlify/unplugin-vue-i18n - npm
If false is specified, Vue I18n (vue-i18n) package.json module field will be used. For more details, See here. compositionOnly. Type: ...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found