Search code examples
typescriptfunctional-programming

Is there a way for Typescript to detect correct overloaded function on composition?


While playing with FP in Typescript I moved to overloaded functions and now have a problem of Typescript not detecting the correct overloaded parameter types.

/** parses as `Date` instance */
export function asDate(val: string | number | Date): Date;
export function asDate(val: string | number | Date | null | undefined): Date | null;
export function asDate(val: unknown) {
  return val instanceof Date ? val : typeof val === 'number' || typeof val === 'string' ? new Date(val) : null;
}

export function apply<T, R>(fn: (arg: T) => R) {
  return fn;
}

const date0 = asDate(123); // detected as Date
const date1 = apply(asDate)(123); // detected as Date | null

I would expect date1 to infer that it is called with a number and detect return type Date but it takes the most open type and detects Date | null instead. Is there a way to fix it?


Solution

  • Actually, it is possible although I'm not quite sure why your approach does not work.

    It works by letting the compiler infer the type of the passed function:

    export function apply<F extends (args: any) => any>(fn: F) {
        return fn;
    }
    

    In the end:

    /** parses as `Date` instance */
    export function asDate(val: string | number | Date): Date;
    export function asDate(val: null | undefined): null;
    export function asDate(val: unknown) {
        return val instanceof Date ? val : typeof val === 'number' || typeof val === 'string' ? new Date(val) : null;
    }
    
    export function apply<F extends (args: any) => any>(fn: F) {
        return fn;
    }
    
    const date0 = asDate(123); // detected as Date
    const date1 = apply(asDate)(123); // detected as Date
    const date3 = apply(asDate)(null); // detected as null
    const date4 = apply(asDate)(true); // TS2769: No overload matches this call