Writing an interface for type, or function that returns type

96 Views Asked by At

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?

1

There are 1 best solutions below

0
On BEST ANSWER

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