TypeScript Function Signatures and Overloading Dos/Don'ts

preview_player
Показать описание
This is a deep dive into function signatures and reveals some insights into writing APIs.
Рекомендации по теме
Комментарии
Автор

The whole "overloading" thing in TypeScript is quite useless. I strongly believe that the only reason it was introduced is to cover existing libraries that are following the function overloading pattern.

The alternative you described in not so uncommon as you stated, it is actually pretty common thing. The main rule of coding is to keep your code readable, and overloads usually are not.

If function should accept different param types and do the same work not depending on parameter type itself, you would be better using generics instead of overloading.
If your function accept one parameter and it could be either string or number (for example checking if a string/number is numeric value), then you will be better using union type.
If your function accepts several parameters but some of them are optional, you could better use single object-type parameter with optional fields and you can still have callback at last place.

But the most important thing in your example is with your urlRead functions. They should not be implemented as overloads, because well they are not THE SAME functions. Reading url with query, and reading url with query+hash are two DIFFERENT functions that do DIFFERENT things. Of course, they share the same result type, but still they do different things. Thinking this way we could implement Array.filter and Array.map functions as one with overloads depending on parameters passed to them, but why should we do it? They both return a new array, but their purpose is different.

For example, lets say you have an User class/module that will retrieve users from whatever source. You can either find user by its ID (number type) or by user's accessToken (a string type). Why one would every think implementing it as single function that behave differently depending on parameter passed? I'd instead create two functions, User.fromId( id:number ) and User.fromAccessToken( accessToken: string ) because while they both return an user instance, their purpose is different. Having one function may seem nice at first, but it has worse readability when you notice User.get( query ) somewhere in code, then you will scroll through source code to find out query variable, but it is a "parseQuery" function result, so you will open another module to check what return type of this function is, and well... you would see that it is overloaded as well, haha, and accepts several different inputs, so you are moving back towards your first source to examine what parameters are passed to this function aaand so on. In the other hand if you look and see User.fromAccessToken(query) function then you can be sure that query contains user's access token.

So all TypeScripts programmers, please never use overloading in your code, thank you.

martinchya