Skip to content

Instantly share code, notes, and snippets.

@Tsugami
Last active June 10, 2022 16:42
Show Gist options
  • Save Tsugami/fc36329a1261982205875a1e744644f5 to your computer and use it in GitHub Desktop.
Save Tsugami/fc36329a1261982205875a1e744644f5 to your computer and use it in GitHub Desktop.
i18next types
type TokenTranslation<Namespaces, R extends boolean = false> = Extract<
keyof {
[Key in Extract<keyof Namespaces, string> as Namespaces[Key] extends
| string
| number
? `${Key}`
: `${Key}${R extends true ? "." : ":"}${TokenTranslation<
Namespaces[Key],
true
>}`]: unknown;
},
string
>;
// (╯°□°)╯︵ ┻━┻
type ResultTranslation<Obj, T extends string> = T extends keyof Obj
? Obj[T]
: T extends `${infer Key}:${infer R}` | `${infer Key}.${infer R}`
? Key extends keyof Obj
? ResultTranslation<Obj[Key], R>
: never
: never;
type i18NextProps<
T extends string,
Acc extends Record<string, string> = {}
> = T extends `${string}{${infer Key}}${infer Rest}`
? i18NextProps<Rest, Acc & { [K in Key]: unknown }>
: Acc;
const translation = <
N extends Record<string, any>,
T extends TokenTranslation<N>,
P extends i18NextProps<ResultTranslation<N, T>>
>(
_obj: N,
_text: T,
_props: P extends Record<string, never> ? null : P
): void => {
return;
};
const namespaces = {
common: {
"hello-world": "awdiojaodjiaw",
},
commands: {
ping: {
description: "show ping",
pong: "Ping! {ms}",
},
},
} as const;
translation(namespaces, "common:hello-world", null); // ok
translation(namespaces, "common:hello-world", {}); // error
translation(namespaces, "commands:ping.description", null); // ok
translation(namespaces, "commands:ping.description", {}); // error
translation(namespaces, "commands:ping.pong", { ms: 42352 }); // ok
translation(namespaces, "commands:ping.pong", {}); // error
translation(namespaces, "commands:ping.pong", null); // error
translation(namespaces, "wdokapdjawiowfjio"); // deve da error
@Tsugami
Copy link
Author

Tsugami commented Jun 10, 2022

export type ObjectToken<Namespaces> = Extract<
  keyof {
    [Key in Extract<keyof Namespaces, string> as Namespaces[Key] extends
      | string
      | number
      ? `${Key}`
      : Namespaces[Key] extends (infer T)[]
      ? `${Key}.${number}.${ObjectToken<T>}`
      : `${Key}.${ObjectToken<Namespaces[Key]>}`]: unknown;
  },
  string
>;

export type ObjectValueByPath<
  O,
  P extends ObjectToken<O>
> = P extends `${infer Key}.${infer Rest}`
  ? Key extends keyof O
    ? ObjectValueByPath<O[Key], Rest extends ObjectToken<O[Key]> ? Rest : never>
    : never
  : P extends keyof O
  ? O[P]
  : never;

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment