react-i18next
react-i18next copied to clipboard
How to extract translation keys from the parameter of `t` to the separate type?
How can I extract the type of the possible keys from t function? It works perfectly when I use it inside components after useTranslation() call, so I want to use the type anywhere, for example, as the type of a prop.
To Reproduce
I tried something like this, but it looks weird and I get the error TS2589: Type instantiation is excessively deep and possibly infinite
type TranslationKeys = Parameters<ReturnType<typeof useTranslation>['t']>[0]
My declaration file:
import en from 'assets/i18n/en-US.json';
type Resources = typeof en;
declare module 'react-i18next' {
interface CustomTypeOptions {
resources: Resources;
}
}
I can construct it on myself by Resources manipulations, but it should be possible to do it "natively"
Your Environment
- i18next version: 21.8.1
- react-i18next: 11.16.9
- typescript: 4.6.4
related #1500
This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.
Hey @vadimyen, you should be able to accomplish it with the TFuncKey.
type TranslationKeys = TFuncKey<'translation'>
The generic passed to TFuncKey is the namespace that you want the keys to be inferred with. It accepts singles and multi namespaces (array).
If you don't pass any argument, it'll default with the defaultNS.
This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.
Hello @pedrodurek or @adrai! I'm trying to use TFuncKey<'translation'> to type a wrapped t function, however something is a bit off. Would you be able to help me figure this out?
In the screenshot below, foo is a simple function which wraps the t function, and types the key using TFuncKey. If I call foo with a valid key, the return type is not a string, but also includes the types in the 2nd level of translations from my json file, for some reason.

If I call t directly with the same key, I get the expected string return type.

This wrapping may seem a bit pointless but we've got some logic to execute before each translation and I was hoping wrapping like this may do the job. I can create a codesandbox next week if that'll help.
I believe the issue with your foo function is you need to add the generic type to TFuncKey, for example TFuncKey<"YourNamespaceHere">
I'm having a quite similar issue here.
I've tried doing type TranslationKeys = TFuncKey<'translation'>, and, although my translation keys fit in there (ie. I can do things like const v: TranslationKeys = 'user.acceptedTerms'), it doesn't work when I try to wrap a function - it would seem TranslationKeys has more than t would get.
Namely, I get essentially the same error as @develohpanda when trying to wrap t
Hi all! It may be late, but I've been experiencing this issue today and managed to fix it with the following steps:
Step 1
Upgrade Typescript to version > 5.1.6. This is required to enhance autocompletion and fix the annoying recursive issue.
Step 2
Follow i18next guidelines to properly extend its global type. Here there is my implementation:
declare module 'i18next' {
interface CustomTypeOptions {
defaultNS: <-- your default namespace
ns: <-- your namespaces
resources: <-- your resources;
}
}
I've put this file under PROJECT_ROOT/@types/.
Step 3
Create a file in which you create the following type to use to properly type localized string that match i18next.t argument.
import {ParseKeys} from 'i18next';
type NS = <your namespaces array>
type DefaultNS = <your default namespace>;
export type LocalizedLabelKey =
| ParseKeys<NS, {}, DefaultNS>
| TemplateStringsArray;
Conclusion
Please bear in mind that it may not work with your project requirements. My project is fairly simple and I don't leverage i18next to its full scope. I haven't tested this implementation with custom key prefixes or with all the options that you can pass to i18next.t function itself. You can play around with LocalizedLabelKey type and ParseKeys generics to tweak this implementation and match your requirements.
I hope that you will find it helpful.
Cheers!