Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

TypeScript function overloading with enum

I'm running into a little issue when trying to implement function overloading with TypeScript in conjunction with an enum being passed as a parameter, and a second argument whose type depends on the enum.

For example:

  • If the enum is FOO, then the second argument is of a string type
  • If the enum is BAR, then the second argument is of a number type
  • If the enum is BAZ, there is no second argument

The code I have is as follow, but somehow TypeScript throws an error because even when I'm checking the first argument against the enum, intellisense does not narrow down the type of the second argument: fieldValue is always string | number.

enum ViewName {
    FOO = 'foo',
    BAR = 'bar',
    BAZ = 'baz'
}

function myFunction(viewName: ViewName.FOO, stringValue: string);
function myFunction(viewName: ViewName.BAR, numberValue: number);
function myFunction(viewName: ViewName.BAZ);
function myFunction(viewName: ViewName, fieldValue?: string | number): void {

    if (viewName === ViewName.FOO) {
        fieldValue = fieldValue.reverse();
    }

    if (viewName === ViewName.BAR) {
        fieldValue *= 2;
    }

    if (viewName === ViewName.BAZ) {
        return console.log('No fieldvalue is supplied by BAZ.');
    }

    console.log(fieldValue);
}

The code can also be viewed on TypeScript Playground.

like image 928
Terry Avatar asked Jun 18 '26 17:06

Terry


1 Answers

Typescript will not narrow the type of the second parameter based on the type of the first parameter. This feature is just not implemented in typescript.

You can either add extra checks to the if to let the compiler narrow the type of fieldValue

function myFunction(viewName: ViewName.FOO, stringValue: string);
function myFunction(viewName: ViewName.BAR, numberValue: number);
function myFunction(viewName: ViewName.BAZ);
function myFunction(viewName: ViewName, fieldValue?: string | number): void {

    if (viewName === ViewName.FOO && typeof fieldValue === "string") {
        fieldValue = fieldValue.reverse();
    }
    else if (viewName === ViewName.BAR && typeof fieldValue === 'number') {
        fieldValue *= 2;
    }

    console.log(fieldValue);
}

Or you can just use a type assertion:

function myFunction(viewName: ViewName.FOO, stringValue: string);
function myFunction(viewName: ViewName.BAR, numberValue: number);
function myFunction(viewName: ViewName.BAZ);
function myFunction(viewName: ViewName, fieldValue?: string | number): void {

    if (viewName === ViewName.FOO) {
        fieldValue = (fieldValue as string).reverse();
    }
    else if (viewName === ViewName.BAR) {
        fieldValue =  (fieldValue as number) * 2;
    }

    console.log(fieldValue);
}

A bigger change would be to use a discriminated union, that will allow the compiler to narrow the type of the parameter in a more expected way:

function myFunction(p: { viewName: ViewName.BAZ }
    | { viewName: ViewName.BAR, fieldValue: number }
    | { viewName: ViewName.FOO, fieldValue: string }): void {

    if (p.viewName === ViewName.FOO) {
        p.fieldValue =  p.fieldValue.reverse();
    }
    else if (p.viewName === ViewName.BAR) {
        p.fieldValue *=  2;
    }

    console.log(fieldValue);
}
like image 166
Titian Cernicova-Dragomir Avatar answered Jun 20 '26 10:06

Titian Cernicova-Dragomir



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!