Typescript Why You Should Avoid Explicit Function Generics If Possible
Tags: javascript, programming, webdev, typescript
Published: 2022-12-15 23:40:51

There are few reasons, the obvious reason is: optimal developer experience

An intelligence type do the most work for you, it is more automate and you write less code

But there is one very important reason: it does not work well with union

to understand this, observe the below example:

```ts
type SomeType = {
    name: string;
    quantity: number;
};
const someFunc = <Key extends keyof SomeType>(
    key: Key,
    value: SomeType[Key],
) => {
    // ...
};

// not explicit generics
someFunc("name", "John") // OK
someFunc("name", 10) // Error as desired
someFunc("quantity", "John") // Error as desired
someFunc("quantity", 10) // OK

// explicit generics
someFunc<"name" | "quantity">("name", 10) // wrong, but no error
```


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/mcxuealjvxcergemnnvw.png)



[playground](https://www.typescriptlang.org/play?#code/C4TwDgpgBAyg9gWwgFXNAvFA3gKCvqAOwEMkAuKAZ2ACcBLQgcwG48CBHAV2MODtAqFOCAEYQarAL6sAxnELUqiCADFOhGVEwAeANIQQUCAA9gEQgBNKUANYG4AM1jLUkAHwAKNvjsgK+kAAabygAN2IAG04ICngkVwgAbQCAXWCASi03bBCAelyoADpinGkcHEplNQ0PACISJFrAqFqAKTgAC0JazPyoAHldCqr1GTqGiCaoAEYABl6CgFEaGjgaKGJrCwhKOhoIC2GkarHarh4+UCm2zu6FqGXV9c2obd39w8rj0brz3n4QFM5vdBuUvqpRtp6qRJlAAD4tP6XQGeaGNZrAqB9ADuqyYzREnGARDgRhWayAA)

now, to be fair, this is not developers fault and should be not developers responsibility

ideally TS should handle case like this correctly, but unfortunately we don't have much option

except with this magic utility...

```ts
type UnionToIntersection<U> = 
  (U extends any ? (k: U)=>void : never) extends ((k: infer I)=>void) ? I : never

type IsUnion<T> = [T] extends [UnionToIntersection<T>] ? false : true

type SomeType = {
    name: string;
    quantity: number;
};
const someFunc = <Key extends keyof SomeType>(
    key: IsUnion<Key> extends true ? "No Union!":Key,
    value: SomeType[Key],
) => {
    // ...
};

someFunc<"name" | "quantity">("name", 10) //  error as expected

// still works as normal
someFunc("name", "John") // OK
someFunc("name", 10) // Error as desired
someFunc("quantity", "John") // Error as desired
someFunc("quantity", 10) // OK
```


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/zx5j0rurwv5xyuepkx2k.png)



[playground](https://www.typescriptlang.org/play?#code/C4TwDgpgBAqgdgSwPZwCpIJJ2BATgZwgGNhk4AeGAPigF4oAoKKAChiggA8c4ATfKAEM4IKAH5WAawBcsAJS0qANyQJeUWXAhK8cjtwh8BLFjKgI4AMzxQMC5at56JGDVC07cDBqEi388GTkqDT0ANqoALr6PPxQYYEo6Fg4BMSkKMFU0RKWggA2hG7AuACuEN6+0ABiSEh0-okUAOSCAEZEzVAAPlDNvBCWzTQA9CNQJeU+4NAAQoK4DRgBiJmtHcNQY1B5hRXTfgDKSAC2EKgzDQDeTMzugmey+CUWAOYA3LfMAI6lwqSgTSlE5tPCfAC+nyIKGeUHwpwg1VKcCIDXIAGkIKIuLEBJIsUhLFBjmcLpAqCwvlB8SBZMsmhisTQcYY4pNoBIAEQAOXqTQAhJzpJiQAAaKlKArlWQk84zMIiyLivSKKA3O5bcYAOh1DEh3nhZyRKPInLgDwgnJ6UE5v3+CFAnIpZotnNFUAAjAAGPTbDi4XBIRaCARcSAkCC8bzbZ4IfL5KAAdyDkgEIfcQZOBQYhsRyKILBdZzdNoAUkgABZwTm+8YAeXROYRxoLRct7u9tagAFEA0GhAIBvgELhI02jfnC3bsA6QCXOeWqzXNT2+8HBxBh6Oo7mW1O-jPHR2fSuG0A)

[IsUnion](https://stackoverflow.com/questions/53953814/typescript-check-if-a-type-is-a-union)

Though this is a legit solution, it is not the best solution. As you can see it only warn you about union but do nothing to the other value type. Ideal solution is to show error on the value `10`.

it is also not fun to do this every time, so please avoid explicit function generic if possible


[origin of the question and more case study](https://stackoverflow.com/a/74817815/5338829)