Typescript > 泛型 > 联合约束

Ric*_*ter 1 typescript typescript-generics

为什么打字稿编译器会抛出以下错误:

Operator '+' cannot be applied to types 'T' and 'T'.,

编译时:

export const addNumbersOrCombineStrings = <T extends string | number>(
  param1: T,
  param2: T
): T => param1 + param2
Run Code Online (Sandbox Code Playgroud)

?

jca*_*alz 5

GitHub 中的相关问题是Microsoft/TypeScript#12410。Ryan Cavanaugh在评论中解决了您的具体问题:

T + T其中Textendsstring | number仍然是不允许的——我们认为这不是一个好的用例,因为无论你是否进行串联或添加都是不可预测的,因此人们不应该这样做。

如果您尝试将两种string | number类型添加在一起,也会发生同样的事情:

declare const x: string | number;
x + x; // error!
// Operator '+' cannot be applied to types 'string | number' and 'string | number'.
Run Code Online (Sandbox Code Playgroud)

所以我猜他们是认真的,他们不希望你这样做。您始终可以按照您的意愿改变编译器并使用类型断言禁用类型检查;

export const addNumbersOrCombineStrings = <T extends string | number>(
  param1: T,
  param2: T
): T => (param1 as any) + param2;
Run Code Online (Sandbox Code Playgroud)

但您不想这样做,特别是因为T extends string | number将推断字符串或​​数字文字,这不会给您带来您期望的行为:

const notThree = addNumbersOrCombineStrings(1, 2);
// const notThree: 1 | 2

const notHi = addNumbersOrCombineStrings("h", "i");
// const notHi: "h" | "i"
Run Code Online (Sandbox Code Playgroud)

哎呀,这些结果是文字的并集。为了使用泛型解决这个问题,您可能需要开始使用奇特的条件类型来扩大文字范围:

type SN<T extends string | number> = (T extends string ? string : never) | 
  (T extends number ? number : never);

export const addNumbersOrCombineStrings = <T extends string | number>(
  param1: T,
  param2: SN<T>
): SN<T> =>
  (param1 as any) + param2;

const n = addNumbersOrCombineStrings(1, 2); // const n : number;
const s = addNumbersOrCombineStrings("h","i"); // const s: string;

// and do you even want to support this:
const sn = addNumbersOrCombineStrings(
  Math.random() < 0.5 ? "a" : 1,
  Math.random() < 0.5 ? "b" : 2
); // const sn: string | number;
Run Code Online (Sandbox Code Playgroud)

但也可能存在边缘情况(就像传入的值实际上与上面的情况string | number类似sn)。我开始明白为什么他们不喜欢支持string | number一起添加类型值。无论如何,希望有帮助。祝你好运!