Question:
I have a function where the return type depends on the parameter type. I was able to declare this overload with function
, but not with arrow function , because I get the error:
Cannot redeclare block-scoped variable 'parseToDate2'.
'=>' expected.
See an example below:
// Funciona
function parseToDate<T extends string | null>(date: T): T extends string ? Date : null;
function parseToDate(date: string | null): Date | null {
return typeof date === 'string' ? new Date(date) : null;
}
// Não funciona
const parseToDate2 = <T extends string | null>(date: T): T extends string ? Date : null;
const parseToDate2 = (date: string | null): Date | null =>
typeof date === 'string' ? new Date(date) : null;
Am I declaring the overload wrongly or is it not supported in arrow functions ? If not supported, why?
At first I figured that since it works with function
, it should somehow work with arrow function .
Answer:
You won't be able to use syntax "similar" to function declarations as the TypeScript doesn't understand that various function declarations via arrow functions defined with const
(or even let
) are definitions of overloads.
For overload definitions using that more explicit notation, it's just with function declarations. Refer to documentation.
You have two alternatives:
-
Do not use arrow function
In that case, you'll simply go to the function declaration syntax. This is the way I prefer, since there's not much reason to use arrow function there. In this case, you will be using the notation that the language has chosen for this.
I'm not going to give an example because it's already in the question.
-
Create a new type (with defined overloads) and assign it to the arrow function
You have two ways to do this. Use interfaces or two types of functions joined by the type-intersection operator,
&
.Example that uses interfaces:
interface GetParent { (selector: string): HTMLElement | null; (element: HTMLElement): HTMLElement | null; } const getParent: GetParent = (selector) => { if (typeof selector === 'string') { return document.querySelector(selector)?.parentElement ?? null; } return selector.parentElement; }
Example using intersection of function types:
type GetParentViaSelector = (selector: string) => HTMLElement | null; type GetParentViaElement = (element: HTMLElement) => HTMLElement | null; type GetParent = GetParentViaSelector & GetParentViaElement; const getParent: GetParent = (selector) => { if (typeof selector === 'string') { return document.querySelector(selector)?.parentElement ?? null; } return selector.parentElement; }
I modified the examples to simplify the answer. 🙂 But generics work too.
I should point out that when the return types are different (as in the example in the question), the only way out is to use the explicit overload syntax itself with the function declarations. Apparently this is expected behavior.