4

I want to define a function which takes a callback as a parameter, and that callback's parameters should be required. Typescript correctly reports a callback with a mismatched parameter type but says nothing about callbacks with no expected arguments.

Why does the second on call not error, and is there any way to make it error?

function on(callback: (num: number) => void) {
    callback(5);
}

on((string:bob) => { // typescript error
    console.log("What");
});

on(() => { // no typescript error?
    console.log("What");
});

3 Answers 3

7

There isn't a way to do this.

Callbacks with fewer parameters than the caller provides are extremely common in JavaScript - functions like forEach, map, filter, etc all provide 3 or more arguments but are frequently given 1-parameter functions as callbacks.

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

4 Comments

Right, but I figured Typescript would provide a way to define callbacks with required params. Something like function doThing(callback: (num!: number)... would be cool, as opposed to the ? optional parameter identifier.
But what would be the sense of adding a callback parameter if you don't want to use that parameter in the callback's body?
It may be common in Javascript, but it's also a common source of bugs. I expected that Typescript would provide a way to enforce parameters in a callback... Has anyone found a way to do this?
There isn't a way to do that
0

You could define a type for the handler. Now you can only pass a callback that has a string argument.

// define a handler so you can use it for callbacks
type Handler = (t: string) => void;

function doSomething(t: string): void {
    console.log("hello " + t)
}

function thisFirst(callback: Handler) {
  callback('world') // ok
  callback(4) // not assignable to type 'string'
}

thisFirst(doSomething)

4 Comments

This does not address what the OP is asking. With the code you show it would be possible to have thisFirst(() => console.log("foo")); compile without error. The OP wants that code to give an error because the callback does not have an argument defined on it.
Yeah good point. My solution would be not to use anonymous callbacks at all but just define a type and a function name. In my opinion that results in cleaner, more readable code but I realise that's just my opinion :-)
Anonymous or not is not a factor in the problem here. Take the code you show in your answer, and define doSomething like this: function doSomething(): void {. And remove the reference to t in from doSomething. You can still do thisFirst(doSomething) without getting a compilation error on that call.
True! But how do we solve this then? Why can't we enforce parameters on a callback function?
0

Here's my current solution - hopefully someone comes up with something better

function on<N extends number = never>(
  callback: N extends never ? never : (num: N) => void
) {
  callback(5)
}

on((bob: string) => {
  // typescript error
  console.log('What')
})

on(() => {
  // typescript error
  console.log('What')
})

on((num: number) => {
  // no typescript error
  console.log(num)
})

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.