typescripttypestypescript-genericstype-parameter

Why is the first type parameter better than the second?


I was going through TS documentation when I came across the section Use Fewer Type Parameters. Here, we are presented with 2 examples:

function filter1<Type>(arr: Type[], func: (arg: Type) => boolean): Type[] {
  return arr.filter(func);
}
function filter2<Type, Func extends (arg: Type) => boolean>(
  arr: Type[],
  func: Func
): Type[] {
  return arr.filter(func);
}

According to the description the 1st one is said to be better compared to the 2nd. Although the 2nd has more code, I do not particularly see how it is worse. I do see that Func is being used similar to a type definition but that is it.

If anyone could particularly tell me what the statement

callers wanting to specify type arguments have to manually specify an extra type argument

from the description means, it would be massively helpful.


Solution

  • A caller of a function might want to explicitly provide type parameters when calling a function. Since TypeScript does not have partial type inference, every type parameter would have to be provided.


    Let's look at an example:

    Say you have a function which takes only 'a' | 'b' as its argument.

    function takesOnlyAB(arg: 'a' | 'b') { return true }
    

    And you want to call it within your filter callback.

    filter1(["a", "b"], (arg) => takesOnlyAB(arg)) 
    //                                       ^^^ Argument of type 'string'  
    //                                           is not assignable to parameter of type
    //                                           '"a" | "b"'
    

    You would run into this annoying error. There are multiple ways to fix it. One would be to provide the type parameter of Type explictly.

    // works fine
    filter1<'a' | 'b'>(["a", "b"], (arg) => takesOnlyAB(arg)) 
    

    With filter2, you would have to provide both type parameters.

    filter2<'a' | 'b', (arg: 'a' | 'b') => boolean>(
      ["a", "b"], 
      (arg) => takesOnlyAB(arg)
    ) 
    

    You can see that it is unnecessary effort to type out both type parameters when one would have been enough.


    Playground