Consider a library which exports a run function like below:
runner.ts
export type Parameters = { [key: string]: string };
type runner = (args: Parameters) => void;
export default function run(fn: runner, params: Parameters) {
fn(params);
}
And consider the following code in a separate file:
index.ts
import type { Parameters } from "./runner.ts";
import run from "./runner.ts";
type CustomParams = { hello: string };
function logGenericArgs(args: Parameters): void {
console.log(args);
}
function logHelloFromArgs(args: CustomParams): void {
console.log(args.hello);
}
run(logGenericArgs, { abc: "123" });
run(logHelloFromArgs, { hello: "123" }); /* Argument of type '(args: CustomParams) => void' is not assignable to parameter of type 'runner'.
Types of parameters 'args' and 'args' are incompatible.
Property 'hello' is missing in type 'Parameters' but required in type 'CustomParams'. ts(2345)
*/
Why does TypeScript complain about the different types, when they're perfectly compatible with each other? From my understanding, type Parameters is a generic object with string keys and string values; CustomParams's "hello" key perfectly fits the Parameters's type signature.
How can I make the code in the "runner" library to accept a generic object type, and work nicely with other types that are compatible?
I do not want to use type unknown or any, as that's basically useless. I want the call signature of the run function to express that args is an object, but I do not want to limit the args' type to that specific signature only.
I also do not want to specify the hello key in type CustomParams as optional, because that key should not be optional in the usage of the type CustomParams - and I do not want to add the key hello in type Parameters because it is not required in every use case of the "runner" library.
TypeScript doesn't know that
paramsis supposed to be the parameters offn, but you can easily fix that but adding a generic parameter to associate the two:Now when you call your custom params function:
It's inferred as
which is what we want.
Playground