Home > database >  Typescript - Typing a function with optional argument correctly
Typescript - Typing a function with optional argument correctly

Time:07-11

Suppose we have the following function:

function test<S, T>(obj: S, prop: keyof S, mapper?: (value: S[keyof S]) => T): S[keyof S] | T {
  return typeof mapper === 'function'
    ? mapper(obj[prop])
    : obj[prop];
}

If then I use it without the mapper argument, the type of the return value is not deduced properly:

const value = test({ a: 'stringValue' }, 'a'); // value is of type "unknown"

But if I provide an identity function as the third parameter, it is deduced correctly:

const value = test({ a: 'stringValue' }, 'a', x => x); // value is of type "string"

How should the test function be typed so when we don't provide the mapper argument, the return value's type is deduced correctly?

Playground link

CodePudding user response:

Just use function overloads !

function test<S, T>(obj: S, prop: keyof S): S[keyof S];
function test<S, T>(obj: S, prop: keyof S, mapper: (value: S[keyof S]) => T): T;
function test<S, T>(obj: S, prop: keyof S, mapper?: (value: S[keyof S]) => T): S[keyof S] | T {
    return typeof mapper === 'function'
        ? mapper(obj[prop])
        : obj[prop];
}

const value = test({ a: 'stringValue' }, 'a'); // string

const value2 = test({ a: 'stringValue' }, 'a', x => x);  // string

Playground

CodePudding user response:

The usual approach is to help the compiler by moving more information to the generic variables of the function. Does this work for you? (Playground)

function test<
    Obj,
    Prop extends keyof Obj,
    Mapper extends ((value: Obj[Prop]) => any) | undefined
>(
    obj: Obj,
    prop: Prop,
    mapper?: Mapper
): undefined extends Mapper ? Obj[Prop] : ReturnType<NonNullable<Mapper>> {
    return mapper ? mapper(obj[prop]) : obj[prop];
}

const value1 = test({ a: "123" }, "a");

const value2 = test({ a: "123" }, "a", x => parseInt(x));

The optional mapper makes the code harder to write, but I am pretty sure this code can be simplified further.

  • Related