[SOLVED] Types with different parameters like function overload

Issue

I’m trying to write a type which acts as a function signature that allows to have to different set of parameters:

  • The first case, the function expects a predicate.
  • The second case, the function expects two parameters.

This is the example: Link to TS PlaGround. I also copy the code here just in case:

type T1<Tentity> = (predicate: ((entity: Tentity) => Tentity | void)) => void;
type T2<TEntity> = (propertyName: keyof TEntity, newValue: unknown) => void;
type TCommon<TEntity> = T1<TEntity> | T2<TEntity>;

interface IEntity {
    name: string;
    surname: boolean;
}

const entity : IEntity = { name: 'Foo', surname: true };

const method : TCommon<IEntity> = (param1, param2) => {
    if (typeof(param1) === 'function') {
        param1(entity);
    }

    else {
        (entity[param1] as any)= param2;
    }
}

method('name', 'Bar');
method((entity) => { entity.name = 'Bar'});

As you can see, I expect both calls of method to work correctly.
From what I think, TypeScript/IntelliSense should be smart enough to make this reasoning:

  • Since the first parameter is a function, then we have a T1, therefore I don’t even need the second parameter.
  • Otherwise, the first parameter is a string, thus we have a T2, thus I expect a second parameter as well.

Unfortunately, this is not what’s happening: it seems TypeScript cannot "believe" that param1 can also be a function:

enter image description here

I’m pretty sure this can be done because we have the function overload, but I’ve been able to use them only inside a class. But it’s basically the same thing, expect in this case I’m defining the method as a global variable.

Solution

Use an interface to describe a set of call signatures:

interface TCommon<TEntity> {
    (predicate: ((entity: TEntity) => TEntity | void)): void
    (propertyName: keyof TEntity, newValue: unknown): void;
}

But we aren’t quite done yet. The second parameter is optional in the sense that the first overload doesn’t need a second parameter but the second overload does.

So we mark the second parameter as optional:

const method: TCommon<IEntity> = (param1, param2?: unknown) => {

And that’s it.

Playground

Answered By – kellys

Answer Checked By – Cary Denson (BugsFixing Admin)

Leave a Reply

Your email address will not be published. Required fields are marked *