1

I have the following type definition:

type FuncWithRequiredParams = (a: number, b: number, c:string) => void

const func1: FuncWithRequiredParams = (a: number, b: number, c: string) => {} // works
const func2: FuncWithRequiredParams = (a: number, b: number, c: string, d: boolean) => {} // Error
const func3: FuncWithRequiredParams = (a: number, b: number) => {} // works, but I want to force it to fail

is there any workaround for this?

3
  • 2
    Why do you want to force it to error? There's nothing more annoying than having to type out parameters you'll never ever use in the function. Commented Oct 20, 2022 at 16:10
  • Is this an XY problem? Commented Oct 20, 2022 at 16:12
  • Every day I develop more disdain for TypeScript. Commented Oct 20, 2022 at 16:21

1 Answer 1

2

First, let's be clear that this behavior is in fact correct. In this code:

type FuncWithRequiredParams = (a: number, b: number, c: string) => void;
const func3: FuncWithRequiredParams = (a: number, b: number) => {};

the conversation between you and the compiler looks like this:

TSC: Give me a function that I can call with three arguments.

You: Here's a function with two parameters.

TSC: Ok, I can call that with three arguments, your function will just ignore the third one. I'll take it.

And as caTS points out, usually that's what you want. If a function doesn't even use its third parameter, why type it in the first place?

Now, I assume you have a good reason for wanting this (maybe there's a callback that every implementing function has to always call, or something like that), and it's more about making implementers aware of accidental mistakes.

Here's one solution that might work for you. I imagine your callbacks are going to be passed to some function like registerPlugin or addMiddleware or something along those lines.

If you make that function generic, have the compiler infer the exact type of the callback being passed in, and ensure that the inferred type matches the expected one exactly, you have at least some assurance:

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); // works
registerPlugin(func2); // error
registerPlugin(func3); // error

(playground link)

Just be aware that this is is anything but foolproof (and it can't be, because as I pointed out earlier, the original behavior is technically just fine).

For example, if you explicitly provide the type parameter, the compiler won't complain:

registerPlugin<FuncWithRequiredParams>(func3); // works

And if you explicitly set the type of func3 like you did in your original code:

const func3: FuncWithRequiredParams = (a: number, b: number) => {};

registerPlugin(func3); // works

it compiles as well.

Sign up to request clarification or add additional context in comments.

2 Comments

ooo I think we should use Equals from here just to be safe. This "double" extends kinda works, but to cover all edge cases you need to do something really weird (see linked post).
Interesting read! I'm definitely going to try understanding that solution. Nonetheless, I would argue that it's rather futile to go any further. If you need something stricter than assignability, then a caller can always (completely legally, and not even deliberately) change the compile time type to be exactly what's being asked for, like in the two examples at the end of my post. In the end, all of this is not much more than sternly worded documentation that can help catch some mistakes, but doesn't provide any additional type safety.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.