N
Nuxt8mo ago
Gerbuuun

Typescript nested generic resolves to unknown

Am I missing something? In the following example, shouldn't the type of result resolve to { test: { title: 'test' } }? Instead it says it's of type Record<string, unknown>
function test<T, K extends { nested: Record<string, T> }>(data: K) {
return data.nested;
}

const testdata = {
nested: {
test: {
title: 'Test',
}
}
}

const result = test(testdata);
function test<T, K extends { nested: Record<string, T> }>(data: K) {
return data.nested;
}

const testdata = {
nested: {
test: {
title: 'Test',
}
}
}

const result = test(testdata);
Did I reach the limits of Typescript?
Solution:
In the end I actually went with this: ```ts export default function useTranslation() { const { locale } = useI18n(); ...
TS Playground - An online editor for exploring TypeScript and JavaS...
The Playground lets you write TypeScript or JavaScript online in a safe and sharable way.
Jump to solution
5 Replies
Gerbuuun
GerbuuunOP8mo ago
Here is a reproduction with more context. I have created three solutions but only one does what I want: https://stackblitz.com/edit/vitejs-vite-xkeyve?file=src%2Fmain.ts
Gerben Mulder
StackBlitz
Vitejs - Vite (forked) - StackBlitz
Next generation frontend tooling. It's fast!
JuanP Barba
JuanP Barba8mo ago
The problem at this example is with K definition. Typescript is not able to infer value of T from generic K definition. You should pass this directly to the argument: https://www.typescriptlang.org/play?#code/GYVwdgxgLglg9mABFApgZygHgCoD4AUAJgIZTEBciA3omOqoZQEooRwBOhmG7MYA5gBpEeRAF8AlNQBQiROxRQQ7JCTIA6OhhSEA3NLHTpbMBmT01xRAF4ZcrQ0pVZc8xicvXyGFAA2KSgBybHpAwU9xF0NDYwQzBTQQXygbNyh8VAxLCV0gA
TS Playground - An online editor for exploring TypeScript and JavaS...
The Playground lets you write TypeScript or JavaScript online in a safe and sharable way.
JuanP Barba
JuanP Barba8mo ago
As you are passing the infer to the method argument, you can see how the infer is ok. I would go with solution one.
Gerbuuun
GerbuuunOP7mo ago
Somehow missed that option. Thanks!
Solution
Gerbuuun
Gerbuuun7mo ago
In the end I actually went with this:
export default function useTranslation() {
const { locale } = useI18n();

type Translatable<K, T> = K & { translations: Record<string, T> };
function translate<T, K>(data: Translatable<T, K>) {
const { translations, ...rest } = data;
const definedLocales = computed(() => Object.keys(translations));
const translation = computed(() => definedLocales.value.includes(locale.value) ? translations[locale.value] : translations[definedLocales.value[0]]);
const result = computed(() => ({ ...rest, ...translation.value }));

return toReactive(result);
}

return {
translate,
};
}
export default function useTranslation() {
const { locale } = useI18n();

type Translatable<K, T> = K & { translations: Record<string, T> };
function translate<T, K>(data: Translatable<T, K>) {
const { translations, ...rest } = data;
const definedLocales = computed(() => Object.keys(translations));
const translation = computed(() => definedLocales.value.includes(locale.value) ? translations[locale.value] : translations[definedLocales.value[0]]);
const result = computed(() => ({ ...rest, ...translation.value }));

return toReactive(result);
}

return {
translate,
};
}
It is a translate composable which uses the current locale given by Nuxt i18n. I tried function translate<T>(data: { translations: Record<string, T> }) but that resolved to object instead. See final options on typescript play
TS Playground - An online editor for exploring TypeScript and JavaS...
The Playground lets you write TypeScript or JavaScript online in a safe and sharable way.
Want results from more Discord servers?
Add your server