TypeScript 通用字符串或数字数组的总和

Lee*_*sen 1 typescript typescript-generics

我想创建一个 TypeScript 函数,它将接受字符串或数字数组并返回连接的字符串或数字之和。

我的尝试如下所示:

function arrayCat<T extends number | string>(n: Array<T>): string {
  if (n.length > 0) {
    if (typeof n[0] === 'string') {
      return n.join(', ');
    } else if (typeof n[0] === 'number') {
      const v: Array<any> = n;
      const sum: number = v.reduce((prev: number, curr: number)=> {
         return prev + curr;
      });
      return sum.toString();
    }
  }

  return '';
}

console.log(arrayCat([1, 2])); // Outputs: 3
console.log(arrayCat(['fish', 'cow'])); // Outputs: fish, cow
Run Code Online (Sandbox Code Playgroud)

但回归 TypeScript 似乎const v: Array<any> = n;违背了 TypeScript 的初衷。

有一个更好的方法吗?

axi*_*iac 5

T extends number | stringT坚持numberstring。这意味着Array<T>可能同时包含数字和字符串。

当前的代码愉快地接受 [1, 2, 'fish', 'cow']输入并产生意想不到的结果。

通过将函数签名更改为:

function arrayCat<T extends number[] | string[]>(n: T): string
Run Code Online (Sandbox Code Playgroud)

在这种情况下甚至不需要通用的。也可以写成:

function arrayCat(n: number[] | string[]): string
Run Code Online (Sandbox Code Playgroud)

代码的其余部分看起来不错,但在运行时不能保证输入数组的所有项目与第一项的类型相同。


我重构了代码以一次处理一种情况并验证输入数组的所有项目:

function arrayCat(n: number[] | string[]): string {
    if (n.length === 0) {
        return '';
    }

    if (isStringArray(n)) {
        return n.join(', ');
    }

    if (isNumberArray(n)) {
        return n.reduce((acc, curr) => acc + curr).toString();
    }

    // Here `n` contains values of more than one type or even of other types (not strings or numbers)
    throw new Error(`Unexpected input: ${n}`);
}

//
// Type guards
function isStringArray(n: (string | number)[]): n is string[] {
    return n.every((i) => typeof i === 'string');
}

function isNumberArray(n: (string | number)[]): n is number[] {
    return n.every((i) => typeof i === 'number');
}
Run Code Online (Sandbox Code Playgroud)

网上查一下。