Typescript“ +”运算符如何与泛型和函数一起使用?

时间:2019-08-28 06:35:14

标签: typescript

我有一个函数,该函数需要一些值,并对其执行+运算符和一个2值:

function myFunction(input: number): number {
    return input + 2;
}

如果我输入一个数字,它将把这个数字添加到2

const result = myFunction(2);
console.log('Result: ', result);
// Result: 2

如果我传递一个字符串,它将把这个字符串连接到2

const result = myFunction(");
console.log('Result: ', result);
// Result: "22"

到目前为止一切都很好。现在,我想使用泛型来捕获类型:

function myFunction<T>(input: T): T {
    return input + 2;
}

如果我要使用它来捕获参数的隐式类型,我可以这样做:

const result = myFunction(2);
console.log('Result: ', result);
// Error: `(parameter) input: T. Operator '+' cannot be applied to types 'T' and '2'.`

如您所见,TypeScript返回有关类型和+运算符的错误,我不明白为什么。如果我明确设置类型也是如此:

const result = myFunction<number>(2);
console.log('Result: ', result);
// Error: `(parameter) input: T. Operator '+' cannot be applied to types 'T' and '2'.`

我无法理解为什么它返回+的错误。任何帮助都将受到欢迎!

1 个答案:

答案 0 :(得分:4)

通常,TypeScript +运算符比JavaScript +运算符更具限制性。后者可以在类型之间进行隐式转换,并且在操作数方面更宽容。

与泛型和函数的交互

让我们以您的函数为例。给定myFunction下方的位置,就会出现错误,因为T可以是任何文字(有关兼容类型,请参见下方的TypeScript +运算符部分)。

function myFunction<T>(input: T): T {
  // Operator '+' cannot be applied to types 'T' and '2'.  
  return input + 2; 
}

TypeScript还要求您通过控制流分析来缩小诸如string | number之类的联合类型。

declare const t: string | number;
t + 3; // Operator '+' cannot be applied to types 'string | number' and '3'.

// this works!
if (typeof t === "string") {
  const res = t + 3; // const res: string
} else {
  const res = t + 3; // const res: number
}

不幸的是,generics extending a union type的类型变窄还不能很好地发挥作用:

function myFunction<T extends string | number>(input: T): string | number {
  if (typeof input === "string") {
    return input + 3;
  } else {
    // TypeScript could not narrow here to number, we have to cast.
    const inputNumber = input as number;
    return inputNumber + 3;
  }
}

我想这将是最终版本并回答您的问题。作为增强,一个整洁的事情是实际上返回一个条件类型。因此,当我们输入字符串时,我们希望返回字符串。类似物number -> number。请参见此Playground示例。


TypeScript +operator的可能组合

操作数的类型矩阵(空格表示编译错误;例如,在“其他”和“布尔”类型之间):

+----------+---------+----------+---------+---------+--------+
|          |  Any    | Boolean  | Number  | String  | Other  |
+----------+---------+----------+---------+---------+--------+
| Any      | Any     | Any      | Any     | String  | Any    |
| Boolean  | Any     |          |         | String  |        |
| Number   | Any     |          | Number  | String  |        |
| String   | String  | String   | String  | String  | String |
| Other    | Any     |          |         | String  |        |
+----------+---------+----------+---------+---------+--------+

摘录自规格:

  

binary +运算符要求两个操作数均为Number原语类型或枚举类型,或至少一个操作数为Any类型或String原语类型。枚举类型的操作数被视为具有基本类型Number。如果一个操作数为空值或未定义值,则将其视为具有另一种操作数的类型。如果两个操作数均为Number原语类型,则结果为Number原语类型。如果一个或两个操作数均为String原语类型,则结果为String原语类型。否则,结果的类型为Any。

有些短语似乎有些过时了。数字枚举解析为数字,但字符串枚举被视为字符串。使用nullundefined和数字,无论是否进行严格的设置,都会出现编译错误,使用字符串进行串联。 Playground


背景信息:Javascript +operator

  

加法运算符产生数字操作数或字符串连接的总和。

某些星座,您只能在JavaScript中“执行”:

true + 1 // 2
false + false // 0
1 + undefined // NaN
1 + null // 1; typeof(1+ null) === "number";   // :)
new Date() + new Date() // toString() is invoked for both Date objects implicitly

Playground

希望,对于您的问题范围,这不是太多的文字!

欢呼