'Conditional parameter types depending on an argument

This one is tricky to explain but I have some code that runs various checks on data. There are a lot of different check types, and depending on the check type there are different types of user specified parameters.

Below is a simplified example of what I have but unfortunately the type checking is severely lacking (as shown).

For the below example consider there are three different types of checks, humidity, temp, and version, and for each check the user would specify some parameters. I'd like this parameters to be type checked:

export const CheckTypesArray = ['invalid-humidity', 'high-temperature', 'bad-version'] as const;
export type CheckTypes = typeof CheckTypesArray[number];

const CheckFactory: Record<CheckTypes, (data: any, parameters: any) => boolean> = {
  'high-temperature': (data: any, parameters: { threshold: number }) => {
    return data.temp > parameters.threshold;
  },
  'invalid-humidity': (data: any, parameters: { bounds: [number, number] }) => {
    return data.humidty < parameters.bounds[0] || data.humidty > parameters.bounds[1];
  },
  'bad-version': (data: any, parameters: { badVersion: string }) => {
    return data.version === parameters.badVersion;
  },
};

// example
const sampleData = {
  temp: 80,
  humidity: 105,
  version: 'v1.05',
};

// would like type checking on parameters arg here, as you can see I can pass anything in
const highTemp = CheckFactory['high-temperature'](sampleData, { anything: 100 });


Solution 1:[1]

You're explicitly noting that the type of CheckFactory should be

Record<CheckTypes, (data: any, parameters: any) => boolean

so TypeScript takes you at your word and only checks that references to CheckFactory follow that signature. But that's not actually what you want - you want only particular types of parameters for different types of data.

Simply omit the inaccurate typing for CheckFactory, and TypeScript will infer it properly.

const CheckFactory = {

With that, using, for example

const highTemp = CheckFactory['high-temperature'](sampleData, { anything: 100 });

results in the error

Argument of type '{ anything: number; }' is not assignable to parameter of type '{ threshold: number; }'.


If you like using TypeScript, I'd also recommend always avoiding any - it's so permissive, it's as if there was no type-checking at all. If there's something whose type you don't know, unknown is much safer. (unknown is: "Could be anything." any is: "Could be anything, and ignore TypeScript warnings that result from its use")

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 CertainPerformance