Skip to content

Commit

Permalink
Update t function types to rely on types coming from i18next (#1501)
Browse files Browse the repository at this point in the history
* Update T function types to rely on i18next types

* Bump i18next version

* Fix type declaration file and remove reference from the old type file

* Bump i18next version
  • Loading branch information
pedrodurek committed Oct 20, 2022
1 parent a0eed42 commit 3bfd803
Show file tree
Hide file tree
Showing 7 changed files with 119 additions and 521 deletions.
4 changes: 2 additions & 2 deletions ts4.1/icu.macro.d.ts → icu.macro.d.ts
@@ -1,6 +1,6 @@
import React from 'react';
import { Namespace, DefaultNamespace, TFuncKey, Trans } from '.';
import { i18n } from 'i18next';
import { Trans } from './';
import { Namespace, DefaultNamespace, TFuncKey, i18n } from 'i18next';

export { Trans };

Expand Down
116 changes: 85 additions & 31 deletions index.d.ts
@@ -1,11 +1,18 @@
import i18next, { ReactOptions, i18n, ThirdPartyModule, WithT, TFunction, Resource } from 'i18next';
import i18next, {
ReactOptions,
i18n,
ThirdPartyModule,
Resource,
TFuncKey,
Namespace,
TypeOptions,
TFunction,
KeyPrefix,
} from 'i18next';
import * as React from 'react';

type Omit<T, K> = Pick<T, Exclude<keyof T, K>>;
type Subtract<T extends K, K> = Omit<T, keyof K>;

export type Namespace = string | string[];

export function setDefaults(options: ReactOptions): void;
export function getDefaults(): ReactOptions;
export function setI18n(instance: i18n): void;
Expand All @@ -20,7 +27,7 @@ export function getInitialProps(): {
};

export interface ReportNamespaces {
addUsedNamespaces(namespaces: Namespace[]): void;
addUsedNamespaces(namespaces: Namespace): void;
getUsedNamespaces(): string[];
}

Expand All @@ -30,44 +37,76 @@ declare module 'i18next' {
}
}

export interface TransProps<E extends Element = HTMLDivElement>
extends React.HTMLProps<E>,
Partial<WithT> {
children?: React.ReactNode;
type ObjectOrNever = TypeOptions['allowObjectInHTMLChildren'] extends true
? Record<string, unknown>
: never;
type ReactI18NextChild = React.ReactNode | ObjectOrNever;

declare module 'react' {
interface HTMLAttributes<T> {
children?: ReactI18NextChild | Iterable<ReactI18NextChild>;
}
}

type DefaultNamespace = TypeOptions['defaultNS'];

type TransChild = React.ReactNode | Record<string, unknown>;
export type TransProps<
K extends TFuncKey<N, TKPrefix> extends infer A ? A : never,
N extends Namespace = DefaultNamespace,
TKPrefix = undefined,
E = React.HTMLProps<HTMLDivElement>
> = E & {
children?: TransChild | TransChild[];
components?: readonly React.ReactElement[] | { readonly [tagName: string]: React.ReactElement };
count?: number;
context?: string;
defaults?: string;
i18n?: i18n;
i18nKey?: string;
ns?: Namespace;
i18nKey?: K | K[];
ns?: N;
parent?: string | React.ComponentType<any> | null; // used in React.createElement if not null
tOptions?: {};
values?: {};
shouldUnescape?: boolean;
t?: TFunction;
}
export function Trans<E extends Element = HTMLDivElement>(props: TransProps<E>): React.ReactElement;
t?: TFunction<N, TKPrefix>;
};

export function Trans<
K extends TFuncKey<N, TKPrefix> extends infer A ? A : never,
N extends Namespace = DefaultNamespace,
TKPrefix extends KeyPrefix<N> = undefined,
E = React.HTMLProps<HTMLDivElement>
>(props: TransProps<K, N, TKPrefix, E>): React.ReactElement;

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

export interface UseTranslationOptions {
export interface UseTranslationOptions<TKPrefix = undefined> {
i18n?: i18n;
useSuspense?: boolean;
keyPrefix?: string;
keyPrefix?: TKPrefix;
bindI18n?: string | false;
nsMode?: 'fallback' | 'default';
// other of these options might also work: https://github.com/i18next/i18next/blob/master/index.d.ts#L127
}
export type UseTranslationResponse = [TFunction, i18n, boolean] & {
t: TFunction;

export type UseTranslationResponse<N extends Namespace, TKPrefix = undefined> = [
TFunction<N, TKPrefix>,
i18n,
boolean,
] & {
t: TFunction<N, TKPrefix>;
i18n: i18n;
ready: boolean;
};
export function useTranslation(
ns?: Namespace,
options?: UseTranslationOptions,
): UseTranslationResponse;

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

// Need to see usage to improve this
export function withSSR(): <Props>(
Expand All @@ -84,7 +123,11 @@ export function withSSR(): <Props>(
getInitialProps: (ctx: unknown) => Promise<any>;
};

export interface WithTranslation extends WithT {
export interface WithTranslation<
N extends Namespace = DefaultNamespace,
TKPrefix extends KeyPrefix<N> = undefined
> {
t: TFunction<N, TKPrefix>;
i18n: i18n;
tReady: boolean;
}
Expand All @@ -94,20 +137,24 @@ export interface WithTranslationProps {
useSuspense?: boolean;
}

export function withTranslation(
ns?: Namespace,
export function withTranslation<
N extends Namespace = DefaultNamespace,
TKPrefix extends KeyPrefix<N> = undefined
>(
ns?: N,
options?: {
withRef?: boolean;
keyPrefix?: TKPrefix;
},
): <
C extends React.ComponentType<React.ComponentProps<C> & WithTranslationProps>,
C extends React.ComponentType<React.ComponentProps<any> & WithTranslationProps>,
ResolvedProps = JSX.LibraryManagedAttributes<
C,
Subtract<React.ComponentProps<C>, WithTranslationProps>
>
>(
component: C,
) => React.ComponentType<Omit<ResolvedProps, keyof WithTranslation> & WithTranslationProps>;
) => React.ComponentType<Omit<ResolvedProps, keyof WithTranslation<N>> & WithTranslationProps>;

export interface I18nextProviderProps {
children?: React.ReactNode;
Expand All @@ -118,19 +165,26 @@ export interface I18nextProviderProps {
export const I18nextProvider: React.FunctionComponent<I18nextProviderProps>;
export const I18nContext: React.Context<{ i18n: i18n }>;

export interface TranslationProps {
export interface TranslationProps<
N extends Namespace = DefaultNamespace,
TKPrefix extends KeyPrefix<N> = undefined
> {
children: (
t: TFunction,
t: TFunction<N, TKPrefix>,
options: {
i18n: i18n;
lng: string;
},
ready: boolean,
) => React.ReactNode;
ns?: Namespace;
ns?: N;
i18n?: i18n;
useSuspense?: boolean;
keyPrefix?: TKPrefix;
nsMode?: 'fallback' | 'default';
}

export function Translation(props: TranslationProps): any;
export function Translation<
N extends Namespace = DefaultNamespace,
TKPrefix extends KeyPrefix<N> = undefined
>(props: TranslationProps<N, TKPrefix>): any;
44 changes: 29 additions & 15 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

9 changes: 1 addition & 8 deletions package.json
Expand Up @@ -4,13 +4,6 @@
"description": "Internationalization for react done right. Using the i18next i18n ecosystem.",
"main": "dist/commonjs/index.js",
"types": "./index.d.ts",
"typesVersions": {
">=4.1": {
"*": [
"ts4.1/*"
]
}
},
"jsnext:main": "dist/es/index.js",
"module": "dist/es/index.js",
"keywords": [
Expand Down Expand Up @@ -67,7 +60,7 @@
"eslint-plugin-react": "^7.16.0",
"eslint-plugin-testing-library": "^3.10.1",
"husky": "^3.0.3",
"i18next": "^21.0.0",
"i18next": "^22.0.1",
"jest": "^24.8.0",
"jest-cli": "^24.8.4",
"lint-staged": "^8.1.3",
Expand Down
4 changes: 2 additions & 2 deletions test/typescript/custom-types/custom-types.d.ts
@@ -1,6 +1,6 @@
import 'react-i18next';
import 'i18next';

declare module 'react-i18next' {
declare module 'i18next' {
interface CustomTypeOptions {
defaultNS: 'custom';
resources: {
Expand Down
65 changes: 0 additions & 65 deletions test/typescript/returnTypes.test.ts

This file was deleted.

0 comments on commit 3bfd803

Please sign in to comment.