6

I have the following function and its callback type:

type Callbacks = {
    onSuccess: (a: string) => void;
};

function t(event: string, ...args: [...any, Callbacks]) {

}

It works as expected but one thing, onSuccess function has a string param but TS can't recognize it and says that it has any type but I explicitly set it to string.

t("eventName", "bobo", 123, {onSuccess: (asd) => {
    // "asd" is a string but TS says that it's an any
    // Parameter 'asd' implicitly has an 'any' type
}})

playground link

What should I change in order to let TS recognize the callback's params type because manually specifying them every time is tedious?

P.S. it's a simplified example of my problem

4
  • 1
    I would maybe report this, it looks like a bug to me. TS knows it's a string too, as if you change asd:number it will error. I would post an issue here, github.com/microsoft/TypeScript/issues just double check a similar issue doesn't exist first. Handling implicit types in Typescript, is just as important as checking Types, otherwise we get Type Code bloat, (not good).. Commented Jul 6, 2022 at 11:24
  • 1
    This is a current limitation with contextual typing of function parameters with leading/middle rest elements; it is reported at ms/TS#45972. Until and unless this is changed, the workaround I'd use is to make t generic like this. Does this fully address your question? If so I can write up an answer explaining and elaborating. If not, what am I missing? Commented Jul 6, 2022 at 14:11
  • @jcalz hello, I've checked the playground and it fully addresses my question, thanks! Feel free to write up an answer and I'll approve it :) Commented Jul 6, 2022 at 14:58
  • As a workaround more appropriate to what the author was looking for, I removed my answer. Commented Jul 6, 2022 at 15:58

1 Answer 1

5

This is currently a missing feature in TypeScript. A function whose parameter list has leading or middle rest elements does not seem to benefit from contextual typing of its input parameters when called. There is a request at microsoft/TypeScript#45972 to change this. It's (as of 2022-07-06) marked as "awaiting more feedback", so if you want to see this changed it wouldn't hurt to give it a 👍 and comment with your use case if you think it's compelling. It wouldn't necessarily help, but I wouldn't hurt.

In the meantime, if you want to work around it, you could make t() a generic function in a type parameter corresponding to the leading rest tuple. (The original pull request for leading/middle rest elements at microsoft/TypeScript#41544 mentions that generic types are better supported.)

That would look like

function t<T extends any[]>(event: string, ...args: [...T, Callbacks]) {}

And then it works as desired:

t("hello", "bobo", 123, {
    onSuccess: (asd) => asd.toUpperCase() // asd is seen as string
})

Playground link to code

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

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.