Trying to create a function that'll add 2 numbers or concatenate 2 strings like the following.
type Add = <T extends string | number>(a: T, b: T) => T;
const add: Add = (a, b) => {
if (typeof a === 'string' && typeof b === 'string') {
return a + b;
}
return a + b; // why is this error?, where we've 2 types & we've checked one so only one type is remaining
}
const result = add('a', 'b');
When there are string
& number
types and I've checked one type, why is TypeScript complaining about the other type?
// tsconfig.json
"compilerOptions": {
"target": "ESNext",
"module": "ESNext",
"moduleResolution": "bundler",
"allowSyntheticDefaultImports": true,
"esModuleInterop": true,
"jsx": "preserve",
"jsxImportSource": "solid-js",
"allowJs": true,
"noEmit": true,
"strict": true,
"noImplicitAny": true,
"types": ["vinxi/types/client", "bun-types"],
"isolatedModules": true,
"paths": {
"~/*": ["./src/*"]
}
}
If T
can be string | number
, then it is possible that a: string
and b: number
, or vice versa. TypeScript requires that you only add values of the same type, so you need to handle the merging of different types.
The function declaration needs to be split into 3 cases.
two strings
, and the result will be a string
. (Actually, the first case is optional; I only wrote it for the sake of clarity. Since the third case, where the result of string | number
is a string
, covers this as well.)two numbers
, and the result will be a number
.string
instead of string | number
.If you accept both values of the same type and also a mix of string | number
. In the case of the mix, we know that we should expect a string
result.
type Add = {
// If both a and b are strings, return a string
(a: string, b: string): string;
// If both a and b are numbers, return a number
(a: number, b: number): number;
// If one is a string and the other is a number, return a string
(a: string | number, b: string | number): string;
};
const add: Add = (a: any, b: any) => {
// If both a and b are numbers, return the sum as a number
if (typeof a === 'number' && typeof b === 'number') {
return a + b;
}
// If either a or b is a string, return the concatenation as a string
return (a.toString() + b.toString());
};
// Test cases
const result1 = add(1, 2); // 3 (number)
const result2 = add('a', 'b'); // "ab" (string)
const result3 = add('a', 1); // "a1" (string)
const result4 = add(1, 'b'); // "1b" (string)
// Error cases
const result5 = add(new Date(), 'b'); // error (ts2769)
If you specifically accept only a
and b
of the same type:
type Add = {
// If both a and b are strings, return a string
(a: string, b: string): string;
// If both a and b are numbers, return a number
(a: number, b: number): number;
};
const add: Add = (a: any, b: any): any => {
// If both a and b are numbers, return the sum as a number
if (typeof a === 'number' && typeof b === 'number') {
return a + b;
}
// If either a or b is a string, return the concatenation as a string
return (a.toString() + b.toString());
};
// Test cases
const result1 = add(1, 2); // 3 (number)
const result2 = add('a', 'b'); // "ab" (string)
// Error cases
const result3 = add('a', 1); // error (ts2769)
const result4 = add(1, 'b'); // error (ts2769)
If you accept both values of the same type and also a mix of string | number
. In the case of the mix, we know that we should expect a string
result.
function add(a: string, b: string): string;
function add(a: number, b: number): number;
function add(a: string | number, b: string | number): string;
function add(a: string | number, b: string | number): string | number {
if (typeof a === 'number' && typeof b === 'number') {
return a + b;
}
return String(a) + String(b);
}
// Test cases
const result1 = add(1, 2); // 3 (number)
const result2 = add('a', 'b'); // "ab" (string)
const result3 = add('a', 1); // "a1" (string)
const result4 = add(1, 'b'); // "1b" (string)
// Error cases
const result5 = add(new Date(), 'b'); // error (ts2769)
If you specifically accept only a
and b
of the same type:
function add(a: string, b: string): string;
function add(a: number, b: number): number;
function add(a: string | number, b: string | number): string | number {
if (typeof a === 'number' && typeof b === 'number') {
return a + b;
}
return String(a) + String(b);
}
// Test cases
const result1 = add(1, 2); // 3 (number)
const result2 = add('a', 'b'); // "ab" (string)
// Error cases
const result3 = add('a', 1); // error (ts2769)
const result4 = add(1, 'b'); // error (ts2769)