I am new to Typescript and I am running into an issue with Generic types. I am creating a library that reads our configuration. Due to our configuration being arbitrary JSON we are using the any type. However when a consumer uses this library they should know the shape of the data they expect and I want to make a function for retrieving information from the config that we can pass a type to remove the any type from the chain. Additionally I want this function that retrieves the value from the config to take an optional argument that will be the default value returned if the key is missing from the config. My problem is figuring out how to properly type this function so that the function's return type is either the type we pass in as a generic or the type of the default value while taking into account we may omit the default value argument entirely.
I have boiled down my use case to this really simple example.
/* Our config provider module */
//In our real use, config is loaded from a JSON file that can be an arbitrary shape so we must use any type here
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const config: Record<string, any> = {
'mode': 'alpha'
}
const getConfig = <Result, DefaultValue extends Result | undefined = undefined>(key: string, defaultValue?: DefaultValue): Result | DefaultValue => {
const result = config[key] as Result
return result ?? defaultValue
}
/* In another module */
// The consumer of the config knows what shape they are going to read so we want to break the `any` usage here:
// mode should be of type string | undefined since a default value was not provided
const mode = getConfig<string>('mode')
// mode2 should be of type string | string (or just string) since a default value was provided
const mode2 = getConfig<string>('mode', 'omega')
This example doesn't compile and I get the error:
Type 'Result | DefaultValue | undefined' is not assignable to type 'Result | DefaultValue'. Type 'undefined' is not assignable to type 'Result | DefaultValue'.ts(2322)
Any advice on how I can properly type my getConfig function so that if I pass in a type for the Result and the function will properly infer the type of the defaultValue argument (including undefined) and use that as part of it's return type, while also maintaining that if we do pass an actual value for the defaultValue then the type does not have undefined?
Note: I am aware that what I want will not actually validate the contents of the JSON data structure and will compile just fine but if when parsing the JSON the value doesn't match what we pass in as the generic type it could break at runtime. We will aim to validate the JSON later using a schema or something. For now I just want to figure out how to type this properly.
defaultValuegiven?