How to make a generic add operator in TypeScript that works with numbers and strings
Asked Answered
C

1

7

While learning about generics in TypeScript, I wanted to try to recreate the following JavaScript:

function add(x, y){
    return x + y;
}

I tried like:

type StringOrNumber = string | number;

function add<MyType extends StringOrNumber>(x: MyType, y: MyType): MyType {
    return x + y;
}

This errors with:

error TS2365: Operator '+' cannot be applied to types 'MyType' and 'MyType'.

Why doesn't this work? I'd assume that MyType could be either a string or a number, and once "chosen" TypeScript would know it is either adding two strings or two numbers.

Cotsen answered 31/1, 2019 at 22:44 Comment(1)
But each argument could be either string or number, your current types don't require them to be the same...Turban
A
9

A case that could also happen is that MyType can be string | number which extends StringOrNumber. For example add<string | number>('', 1); is a perfectly valid call to the function with the signature you have defined. A type extending a union type doesn't mean "pick exactly one".

Since your signature makes sense and you are learning about generics so we want to stick with it, we can also turn off type checking at that point. Sometimes typescript really can't figure out your complex scenario and you are left with no other option than to return (x as any) + y to abandon the type checking at this point.

Another way to handle this type of situation is with overloaded signatures like the following

function add(x: string, y: string): string;
function add(x: number, y: number): number;
function add(x: any, y: any): any {
    return x + y;
}

const t1: string = add(10, 1); // Type 'number' is not assignable to type 'string'.
const t2: number = add(10, 1); // OK
const t3: string = add('10', '1'); // OK
const t4: number = add('10', 1); // Argument of type '"10"' is not assignable to parameter of type 'number'.
Aegir answered 31/1, 2019 at 23:16 Comment(4)
Unless you also rely on implicit conversions, i.e. add(1, '2') = 3. While that's anti-typescript, but it depends on your use cases. :)Albuminous
Thanks. I considered that case. Though I couldn't understand why that case could happen. Your explanation of add<string | number> make the problem clear. I assumed either add<string> or add<number> would be allowed.Cotsen
How is the question answered, since even if the user would call "add<string | number>(' ', 1);", typescript could add " " + 1 without errors (as it lets this behaviour)Blim
This is fine as long as you aren't using arrow functions.Corum

© 2022 - 2024 — McMap. All rights reserved.