Skip to content

Commit

Permalink
Add type-safe support to keyPrefix option (#1390)
Browse files Browse the repository at this point in the history
  • Loading branch information
pedrodurek committed Oct 28, 2021
1 parent 791957d commit 008d1b0
Show file tree
Hide file tree
Showing 3 changed files with 55 additions and 14 deletions.
3 changes: 3 additions & 0 deletions test/typescript/custom-types/custom-types.d.ts
Expand Up @@ -10,6 +10,9 @@ declare module 'react-i18next' {
};
alternate: {
baz: 'baz';
foobar: {
barfoo: 'barfoo';
};
};
};
}
Expand Down
17 changes: 17 additions & 0 deletions test/typescript/custom-types/useTranslation.test.tsx
Expand Up @@ -38,6 +38,11 @@ function readonlyArrayNamespace() {
);
}

function keyPrefixOption() {
const [t] = useTranslation('alternate', { keyPrefix: 'foobar' });
return <>{t('barfoo')}</>;
}

function expectErrorWhenNamespaceDoesNotExist() {
// @ts-expect-error
const [t] = useTranslation('fake');
Expand All @@ -61,3 +66,15 @@ function expectErrorWhenUsingArrayNamespaceAndWrongKey() {
// @ts-expect-error
return <>{t('custom:fake')}</>;
}

function expectErrorWhenUsingWrongKeyPrefixOption() {
// @ts-expect-error
const [t] = useTranslation('alternate', { keyPrefix: 'abc' });
return <>{t('barfoo')}</>;
}

function expectErrorWhenUsingRightKeyPrefixOptionAndWrongKey() {
const [t] = useTranslation('alternate', { keyPrefix: 'foobar' });
// @ts-expect-error
return <>{t('abc')}</>;
}
49 changes: 35 additions & 14 deletions ts4.1/index.d.ts
Expand Up @@ -149,12 +149,20 @@ type NormalizeMultiReturn<T, V> = V extends `${infer N}:${infer R}`
: never
: never;

export type TFuncKey<N extends Namespace = DefaultNamespace, T = DefaultResources> = N extends
| (keyof T)[]
| Readonly<(keyof T)[]>
type KeyPrefix<N extends Namespace> = N extends keyof DefaultResources
? Fallback<string, keyof DefaultResources[N]> | undefined
: string | undefined;

export type TFuncKey<
N extends Namespace = DefaultNamespace,
TKPrefix extends KeyPrefix<N> = undefined,
T = DefaultResources
> = N extends (keyof T)[] | Readonly<(keyof T)[]>
? NormalizeMulti<T, N[number]>
: N extends keyof T
? Normalize<T[N]>
? TKPrefix extends keyof T[N]
? Normalize<T[N][TKPrefix]>
: Normalize<T[N]>
: string;

export type TFuncReturn<N, TKeys, TDefaultResult, T = DefaultResources> = N extends (keyof T)[]
Expand All @@ -163,17 +171,20 @@ export type TFuncReturn<N, TKeys, TDefaultResult, T = DefaultResources> = N exte
? NormalizeReturn<T[N], TKeys>
: Fallback<TDefaultResult>;

export interface TFunction<N extends Namespace = DefaultNamespace> {
export interface TFunction<
N extends Namespace = DefaultNamespace,
TKPrefix extends KeyPrefix<N> = undefined
> {
<
TKeys extends TFuncKey<N> | TemplateStringsArray extends infer A ? A : never,
TKeys extends TFuncKey<N, TKPrefix> | TemplateStringsArray extends infer A ? A : never,
TDefaultResult extends TFunctionResult = string,
TInterpolationMap extends object = StringMap
>(
key: TKeys | TKeys[],
options?: TOptions<TInterpolationMap> | string,
): TFuncReturn<N, TKeys, TDefaultResult>;
<
TKeys extends TFuncKey<N> | TemplateStringsArray extends infer A ? A : never,
TKeys extends TFuncKey<N, TKPrefix> | TemplateStringsArray extends infer A ? A : never,
TDefaultResult extends TFunctionResult = string,
TInterpolationMap extends object = StringMap
>(
Expand Down Expand Up @@ -208,22 +219,32 @@ export function Trans<

export function useSSR(initialI18nStore: Resource, initialLanguage: string): void;

export interface UseTranslationOptions {
export interface UseTranslationOptions<
N extends Namespace = DefaultNamespace,
TKPrefix extends KeyPrefix<N> = undefined
> {
i18n?: i18n;
useSuspense?: boolean;
keyPrefix?: string;
keyPrefix?: TKPrefix;
}

type UseTranslationResponse<N extends Namespace> = [TFunction<N>, i18n, boolean] & {
t: TFunction<N>;
type UseTranslationResponse<N extends Namespace, TKPrefix extends KeyPrefix<N>> = [
TFunction<N, TKPrefix>,
i18n,
boolean,
] & {
t: TFunction<N, TKPrefix>;
i18n: i18n;
ready: boolean;
};

export function useTranslation<N extends Namespace = DefaultNamespace>(
export function useTranslation<
N extends Namespace = DefaultNamespace,
TKPrefix extends KeyPrefix<N> = undefined
>(
ns?: N | Readonly<N>,
options?: UseTranslationOptions,
): UseTranslationResponse<N>;
options?: UseTranslationOptions<N, TKPrefix>,
): UseTranslationResponse<N, TKPrefix>;

// Need to see usage to improve this
export function withSSR(): <Props>(
Expand Down

0 comments on commit 008d1b0

Please sign in to comment.