admin管理员组

文章数量:1313011

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');

Playground Link

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/*"]
    }
  }

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');

Playground Link

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/*"]
    }
  }
Share Improve this question asked Feb 1 at 10:52 Md. A. ApuMd. A. Apu 1,2502 gold badges19 silver badges40 bronze badges
Add a comment  | 

1 Answer 1

Reset to default 1

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.

  • Function Overloads - TypeScript Docs

The function declaration needs to be split into 3 cases.

  • In the first case, it receives 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.)
  • In the second case, it receives two numbers, and the result will be a number.
  • The third case is your original case, BUT here the result will be a string instead of string | number.

Arrow Function Syntax

  • TypeScript overload arrow functions - StackOverflow

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.

  • TypeScript Playground
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:

  • TypeScript Playground
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)

Function Declaration

  • TypeScript function overloading

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.

  • TypeScript Playground
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:

  • TypeScript Playground
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)

本文标签: Why TypeScript complains on concatonation of stringnumber types with ()Stack Overflow