Skip to content

Instantly share code, notes, and snippets.

@captain-yossarian
Created November 3, 2021 12:47
Show Gist options
  • Save captain-yossarian/b9d33fe00003e53b1ab41dad7e712237 to your computer and use it in GitHub Desktop.
Save captain-yossarian/b9d33fe00003e53b1ab41dad7e712237 to your computer and use it in GitHub Desktop.
useTranslation typings
type Dict = typeof dict
type KeysUnion<T, Cache extends string = ''> =
T extends PropertyKey ? Cache : {
[P in keyof T]:
P extends string
? Cache extends ''
? KeysUnion<T[P], `${P}`>
: Cache | KeysUnion<T[P], `${Cache}.${P}`>
: never
}[keyof T]
type RemoveDot<T extends string> = T extends `.${infer Tail}` ? Tail : T;
type ExtractString<T extends string, U extends string, Result extends string = ''> =
T extends `${infer Head}${infer Tail}` ? `${Result}${Head}` extends U ? Tail : ExtractString<Tail, U, `${Result}${Head}`> : Result
type ValidPrefix<T extends string, U extends string> = T extends `${U}${string}` ? Exclude<T, U> : never
type ConcatNamespaceWithPrefix<N extends string, P extends string> = `${N}.${P}`
type Values<T> = T[keyof T]
type Elem = string;
type Acc = Record<string, any>
// (acc, elem) => hasProperty(acc, elem) ? acc[elem] : acc
type Predicate<Accumulator extends Acc, El extends Elem> =
El extends keyof Accumulator ? Accumulator[El] : Accumulator
type Reducer<
Keys extends Elem,
Accumulator extends Acc = {}
> =
Keys extends `${infer Prop}.${infer Rest}`
? Reducer<Rest, Predicate<Accumulator, Prop>>
: Keys extends `${infer Last}`
? Predicate<Accumulator, Last>
: never
type UseTranslationsProps<D = typeof dict> =
(() => <Prefix extends KeysUnion<D>>(prefix: Prefix) => Reducer<Prefix, D>)
& (
<
ValidKeys extends KeysUnion<D>,
Namespace extends ValidKeys
>(namespace?: Namespace) =>
<Prefix extends RemoveDot<ExtractString<ValidPrefix<KeysUnion<Dict>, Namespace>, Namespace>>>(
prefix: Prefix
) => Reducer<ConcatNamespaceWithPrefix<Namespace, Prefix>, D>
)
declare const useTranslations: UseTranslationsProps;
const dict = {
one: {
two: {
three: "3",
foo: "bar"
}
},
bar: {
baz: 2
}
} as const
{
const t = useTranslations() // ok
const ok = t('one') // {two: ....}
}
{
const t = useTranslations('one.two') // ok
const ok = t('three') // 3
}
{
const t = useTranslations() // ok
const ok = t('three') // expected error
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment