So I have a type map of format { 'type': type } and want to use it in a generic function to "dynamically" determine the return type, but well it doesn't work.
Here's the code:
// Using type instead of interface. I believe it doesn't make any difference?
type SupportedPropertyTypes = {
string: string,
number: number,
boolean: boolean,
object: any
}
type PropertyType = keyof SupportedPropertyTypes
type PropertyDefinition<T extends PropertyType, N = false> = {
type: T,
nullable?: N,
fallback?: PropertyValue<T,N> | (() => PropertyValue<T,N>)
}
type StorageConfig = {
namespace: string,
properties: {
[key: string]: PropertyDefinition<PropertyType>
}
}
type PropertyValue<T extends PropertyType, N = false> = SupportedPropertyTypes[T]
| (() => SupportedPropertyTypes[T])
| (N extends true ? null : never)
const config = {
namespace: 'foo',
properties: {
foo: { type: 'string' },
bar: { type: 'number', fallback: 1338 },
baz: { type: 'boolean', nullable: true },
complicatedThing: {
type: 'object',
nullable: true,
fallback: () => ({
foo: 'bar',
bar: 'baz',
arr: [1,2],
})
}
}
}
function getFallback<TProps extends StorageConfig['properties'], T extends keyof TProps> (key: T, props: TProps) {
return typeof props[key].fallback == 'function'
? props[key].fallback()
: props[key].fallback
}
// Expected: const foo: { foo: string, bar: string, arr: number[] }
// Got: error
const foo = getFallback('complicatedThing', config.properties)
And here goes the error:
Argument of type '{ foo: { type: string; }; bar: { type: string; fallback: number; }; baz: { type: string; nullable: boolean; }; complicatedThing: { type: string; nullable: boolean; fallback: () => { foo: string; bar: string; arr: number[]; }; }; }' is not assignable to parameter of type '{ [key: string]: PropertyDefinition<keyof SupportedPropertyTypes, false>; }'.
Property 'foo' is incompatible with index signature.
Type '{ type: string; }' is not assignable to type 'PropertyDefinition<keyof SupportedPropertyTypes, false>'.
Types of property 'type' are incompatible.
Type 'string' is not assignable to type 'keyof SupportedPropertyTypes'.(2345)
Wrote this code based on solutions from here and here but I'm probably still missing something.
getFallback()doesn't need to care about it, and you could write it like this. Note that your implementation doesn't call the fallback method, so you should be expectingfooto be a function and not a value the function returns. If that's wrong you should edit the code to be a proper minimal reproducible example. Anyway, does this address the question sufficiently? If so I could write up an answer explaining; if not, what am I missing?fallbackalways exists which is not the case (see thePropertyDefinitiontype in my code snippet -fallbackis optional). If you passfooinstead ofcomplicatedThingit won't work. See here. The problem is we never know whetherfallbackis there or not - if there's no fallback, I just wantundefined.fallbackoptional as shown here then? Would that work now?