I have an object containing some default configuration. Some of its values cannot be defined statically and need to be calculated at runtime. To apply these defaults to an object I'll be applying any static values, and executing and applying the return of any functions.
const SETTINGS = {
prop1: true,
prop2: (config: Config): boolean => config.prop2,
prop3: (config: Config): number => config.prop2,
prop4: 0,
} as DefaultSettings
Writing an interface for this object is difficult. Any given property can be either a static value or a function that returns a value. I want the interface to be able to represent multiple objects of this kind, where the property names and property types are the same, but any property can be either a value or a function.
interface DefaultSettings {
prop1: boolean
prop2: boolean
prop3: number
prop4: number
}
The above interface assumes that all properties are static values, which is incorrect.
How do I type a value that may or may not be a function?
To make a property have two (or more) different types you can use the union operator
interface DefaultSettings {
prop1: boolean | ((config: Config) => boolean);
prop2: boolean | ((config: Config) => boolean);
prop3: number;
prop4: number;
}
To not repeat yourself, you can create a type for this as well:
type ConfigBoolean = boolean | ((config: Config) => boolean);
interface DefaultSettings {
prop1: ConfigBoolean;
prop2: ConfigBoolean;
prop3: number;
prop4: number;
}
You can even go further, by using generics. If for instance the number
can also be either a primitive or a function returning that primitive:
type ConfigType<T> = T | ((config: Config) => T);
interface DefaultSettings {
prop1: ConfigType<boolean>;
prop2: ConfigType<boolean>;
prop3: ConfigType<number>;
prop4: ConfigType<number>;
}
The parentheses around the function type are necessary, otherwise the compiler thinks: boolean | (config: Config)
, and gets confused after that :). If you would turn it around: (config: Config) => boolean | boolean
, it will still be ambiguous. In this case, the compiler will think that the type is a function which returns a boolean or a boolean, so that's odd as well