To start off, it's important to clarify that this behavior is indeed correct. Consider the following code snippet:
type FuncWithRequiredParams = (a: number, b: number, c: string) => void;
const func3: FuncWithRequiredParams = (a: number, b: number) => {};
The interaction between you and the compiler can be visualized as follows:
TSC: I need a function that requires three arguments.
You: Here's a function with only two parameters.
TSC: That's alright, I'll use it with three arguments and simply ignore the third one. It still meets my requirement.
As noted by caTS, this is typically the desired behavior. If a parameter is not utilized within a function, there may not be a need to explicitly define it in the type declaration.
If you have a specific reason for wanting this setup (perhaps there's a compulsory callback that every implementing function must invoke), the focus might shift towards prompting implementers about inadvertent oversights.
One approach that could address your concerns involves making the relevant functions generic, allowing the compiler to infer the exact callback type being passed in and ensuring precise matching against the expected type:
type FuncWithRequiredParams = (a: number, b: number, c: string) => void;
const func1 = (a: number, b: number, c: string) => {};
const func2 = (a: number, b: number, c: string, d: boolean) => {};
const func3 = (a: number, b: number) => {};
type Identical<A, B> = A extends B ? (B extends A ? A : never) : never;
function registerPlugin<T>(f: Identical<T, FuncWithRequiredParams>) {
// ...
}
registerPlugin(func1); // valid
registerPlugin(func2); // invalid
registerPlugin(func3); // invalid
(playground link)
It's worth noting that while this approach provides some level of assurance, it is not foolproof (primarily because the original behavior is technically sound).
For instance, explicitly specifying the type parameter will bypass compiler warnings:
registerPlugin<FuncWithRequiredParams>(func3); // valid
Similarly, if you manually set the type of func3
as demonstrated in your initial code snippet:
const func3: FuncWithRequiredParams = (a: number, b: number) => {};
registerPlugin(func3); // valid
The compilation process will proceed without errors in these scenarios.