I have been trying to use type inference for a specific case.
interface Model {
field1: Date;
field2: number;
}
interface Column<T, K extends keyof T = keyof T> {
field: K;
transformation?: (value: T[K], data: Model) => string;
}
const columns: Column<Model>[] = [
{
field: 'field1',
transformation: (value) => value.getTime()
}
];
In ‘transformation,’ I would like ‘value’ to be of type Date instead of being number | Date.
To achieve this, I created two helper types to get the union of possible ‘field’ types and to correctly infer the type from ‘field’ in the callback.
interface Column<
T,
K extends NestedKeyOf<T>,
V extends NestedValueOf<T, K>,
> {
field: K & string;
transformation?: (value: V, data: Model) => string;
}
for NestedKeyOf
type NestedKeyOf<Type> = Type extends string | number
? never
: {
[Key in TraversableKeys<Type>]: NestedSingleKeyOf<Type, Key>;
}[TraversableKeys<Type>];
type TraversableKeys<Type> = Exclude<keyof Type & (string | number), 'prototype'>;
type NestedSingleKeyOf<Type, Key extends keyof Type> = Key extends string
? IsArray<
Type[Key],
Key | `${Key}.${number}`,
IsComplexObject<Type[Key], Key | `${Key}.${NestedKeyOf<Type[Key]>}`, Key>
>
: never;
type IsArray<O, T, F> = O extends Array<unknown> ? T : F;
type IsComplexObject<O, T, F> = O extends Date | Array<unknown> | Blob
? F
: IsObject<O, T, F>;
type IsObject<O, T, F> = O extends object ? T : F;
for NestedValueOf
type NestedValueOf<Type, Key extends string> = Key extends `${infer Head}.${infer Tail}`
? Head extends keyof Type
? IsNumberFromString<
Tail,
IsArrayValue<Type[Head], NestedValueOf<Type[Head], Tail>>,
NestedValueOf<Type[Head], Tail>
>
: never
: IsKeyOfType<Type, Key>;
type IsArrayValue<O, F> = O extends Array<infer U> ? U : F;
type IsNumberFromString<O, T, F> = O extends `${number}` ? T : F;
type IsKeyOfType<Type, Key> = Key extends keyof Type ? Type[Key] : never;
This way, the type of ‘value’ is correctly inferred in the callback. I can even access different levels of nesting using dots, such as ‘field1.field1-2.field1-2-1,’ or even array positions, inferring the correct type like ‘field1.6’.
From this point, my problem is that in cases with multiple levels of nesting (3 or more) and types with many properties (20–30 or more), it takes a long time to compute the corresponding type. Is there any way to optimize the typing or handle it differently?
user28851393 is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.
1