#Type defition with a function property where function has overloads.

15 messages · Page 1 of 1 (latest)

sleek nebula
#

I have a Tool type like so

type Tool = {
  icon: JSX.Element;
  toolEnum: ClipsToolsEnum;
  tooltip: string;
  isDisabled:
    | ((workspaceId: string, currentSrc: string) => boolean)
    | (() => boolean)
    | ((length: number) => boolean);
};

the isDisabled property should be a function that returns a boolean. But the function arguments can be of multiple type. It can have no arguments, one argument of type number or two arguments of type string. I tried to make it work but I couldnt.

I run a map on Tool array and there is a Button in there where I would use that function

  <Button
    variant={'outline'}
    size={'icon'}
    className='size-12'
    disabled={(() => {
      switch (tool.toolEnum) {
        case ClipsToolsEnum.RESET:
          return tool.isDisabled(workspaceId, '');
        case ClipsToolsEnum.MERGE:
          return tool.isDisabled(length);
        case ClipsToolsEnum.DELETE:
          return tool.isDisabled(length);
        case ClipsToolsEnum.FINISH:
          return tool.isDisabled(length);
        case ClipsToolsEnum.OPEN:
          return tool.isDisabled();
      }
    })()}
    onClick={() => handleToolClick(tool.toolEnum)}
  >
    {tool.icon}
  </Button>

Showing error
"Expected 2 arguments, but got 1.ts(2554)
ClipsTools.tsx(50, 30): An argument for 'currentSrc' was not provided.
(property) isDisabled: (arg0: never, currentSrc: string) => boolean"

It looks as if it expects it to be always the function with two arguments with this implementation.

native island
#

Try creating specific types for each function signature that isDisabled can have and use type guards to determine which function signature is being used.

const isDisabledNoArgs = (fn: Tool['isDisabled']): fn is () => boolean => 
  fn.length === 0;

const isDisabledWithLength = (fn: Tool['isDisabled']): fn is (length: number) => boolean => 
  fn.length === 1 && typeof (fn as any) === 'function';

const isDisabledWithParams = (fn: Tool['isDisabled']): fn is (workspaceId: string, currentSrc: string) => boolean =>
  fn.length === 2 && typeof (fn as any) === 'function';

try using it like:

disabled={(() => {
            switch (tool.toolEnum) {
              case ClipsToolsEnum.RESET:
                if (isDisabledWithParams(tool.isDisabled)) {
                  return tool.isDisabled(workspaceId, '');
                }
                return false; // or some default value
              case ClipsToolsEnum.MERGE:
              case ClipsToolsEnum.DELETE:
              case ClipsToolsEnum.FINISH:
                if (isDisabledWithLength(tool.isDisabled)) {
                  return tool.isDisabled(length);
                }
                return false;
              case ClipsToolsEnum.OPEN:
                if (isDisabledNoArgs(tool.isDisabled)) {
                  return tool.isDisabled();
                }
                return false;
              default:
                return false;
            }
          })()}
          onClick={() => handleToolClick(tool.toolEnum)}
sleek nebula
#

thanks I will try this

uneven bloom
#

@sleek nebula The root issue here is the difference between a union of functions and an overloaded function

#

If you have a union of function types, then the type is saying the function will accept one of those signatures and you don't know which: it's very difficult to call it safely.

sleek nebula
#

Yea I dont understand enough, I opted to take out the isDisabled from Tool and just use the ToolEnum to trigger appropriate functions

uneven bloom
#

If you have an overloaded function, the type is saying that the function will accept all of those signatures

#
type Tool = {
  icon: JSX.Element;
  toolEnum: ClipsToolsEnum;
  tooltip: string;
  isDisabled: {
    (workspaceId: string, currentSrc: string): boolean,
    (): boolean,
    (length: number): boolean,
  }
};
#

Here's what the type for an overloaded function would look like.

sleek nebula
#

yea I should provide then all 3 type of functions for each tool

#

which is not what I want

#

I do understand better now

uneven bloom
#

Yeah - using an overloaded function like this is kind of odd so there's probably some other approach you should be taking.

sleek nebula
#

Yea I made it so that button click is handled by a function that takes in ClipsToolsEnum and then proceeds with the correct function

#

switch case with enum inside the handler function