In a different question I was provided with a great way to strip properties like nameDe
and nameFr
from a type and simply get name
. Shout out @jcalz!
Now my use case got a little more complex - I have nested translated interfaces:
type TranslatedObject<T> = {
[K in keyof T as K extends `${infer Name}${'De' | 'Fr'}` ? Name : K]: T[K];
};
interface Gimmick {
nameDe: string;
nameFr: string;
}
interface Car {
nameDe: string;
nameFr: string;
price: number;
gimmicks: Gimmick[];
}
const tcar: TranslatedObject<Car> = {
name: 'Car name',
price: 69,
gimmicks: [{ name: 'seat ventilation' }], // Error: Type '{ name: string; }' is not assignable to type 'Gimmick'.
};
Notice how name: 'Car name',
works properly but the nested Gimmick
with value { name: 'seat ventilation' }
does not.
Stackblitz example
The solution is pretty straightforward. Just call TranslatedObject
recursively if the property is an object:
type TranslatedObject<T> = {
[K in keyof T as K extends `${infer Name}${'De' | 'Fr'}`
? Name
: K]: T[K] extends object ? TranslatedObject<T[K]> : T[K];
};
Usage:
const tcar: TranslatedObject<Car> = {
name: 'Car name',
price: 69,
gimmicks: [{ name: 'seat ventilation' }], // no error
};