I have a data structure that contains various optional fields with different types that have to be fetched individually and formatted. The formatting functions take concrete values.
I tried doing something like the following minimal working example, but it errors with with Property 'value' does not exist on type 'Data[P]'.
I understand why the problem happens, but I want to make this work. I quick hack would be to cast data[idx][key] as Optional<T>, but can this be done without type casts?
// In my code this is more complex, a simple `T | undefined` doesn't work.
type Optional<T> = { kind: 'none' } | { kind: 'value', value: T};
interface Data {
name: Optional<string>;
id: Optional<number>;
}
function computeIndex(): number {
// Some logic here
return 0;
}
// Format field `key` of `data` using `formatter`.
// Use default `def` if the value is `none`.
function printField<
P extends keyof Data,
T extends Data[P] extends Optional<infer V> ? V : never
>(data: Data[], key: P, formatter: (val: T) => string, def: T): string {
const idx = computeIndex();
const field = data[idx][key];
switch (field.kind) {
case 'none':
return formatter(def);
case 'value':
return formatter(field.value);
}
}