TS 错误地推断路口类型
TS incorrectly inferring intersection type
我们遇到了一个无法解决的 TS 错误,我想知道是否有人知道如何修复它。 TS 似乎在 combo.input
上推断出一个交集类型,这看起来很奇怪(联合类型对我来说更有意义)。
我在下面总结了一个例子。
我们最终只是使用了不同的方法,但我觉得应该有一种方法可以键入函数来修复错误。
const stringFunc = (input: string): string => input;
const numFunc = (input: number): number => input;
const stringCombo = { funct: stringFunc, input: 'hello' };
const numCombo = { funct: numFunc, input: 4 };
type Combo = typeof stringCombo | typeof numCombo;
const processCombo = (combo: Combo) => {
return combo.funct(combo.input);
// Argument of type 'string | number' is not assignable to parameter of type 'never'.
};
这并没有错,更多的是设计限制。 combo.funct
是函数的并集。这意味着它可以是接受 string
的函数或接受 number
的函数,但在调用时无法知道它是哪个。因此,调用 combo.funct
的唯一安全方法是使用可以满足两个函数签名的参数。在这种情况下,该类型将是 number & string
,它会减少到 never
(如果这些函数接受不同的对象类型,则可能有一个值同时满足这两种对象类型)
在这种特殊情况下,函数和参数实际上是相关的,但打字稿不跟踪这一点。它所能看到的是 combo.input
的类型(即 string | number
)不能作为函数联合的参数 combo.funct
.
您可以使用有区别的联合:
const stringFunc = (input: string): string => input;
const numFunc = (input: number): number => input;
const stringCombo = { funct: stringFunc, input: 'hello', type: "string" as const };
const numCombo = { funct: numFunc, input: 4 , type: "number" as const};
type Combo = typeof stringCombo | typeof numCombo;
const processCombo = (combo: Combo) => {
return combo.type === "string"?
combo.funct(combo.input):
combo.funct(combo.input);
};
或者因为在这种情况下我们显然比编译器了解更多,所以我们可以使用类型断言:
const processCombo = (combo: Combo) => {
return combo.funct(combo.input as never);
};
除了 Titian Cernicova-Dragomir 的回答之外,
您还可以将您的类型建模为泛型:
type FunTtoT<T> = (t: T) => T;
const stringFunc: FunTtoT<string> = (input: string): string => input;
const numFunc: FunTtoT<number> = (input: number): number => input;
type Combo<T extends string | number> = { funct: FunTtoT<T>, input: T };
const stringCombo = { funct: stringFunc, input: 'hello' };
const numCombo = { funct: numFunc, input: 4 };
function processCombo<T extends string | number>(combo: Combo<T>) {
return combo.funct(combo.input);
};
const s = processCombo(stringCombo); // inferred to string
const n = processCombo(numCombo); // inferred to number
我更喜欢这种方法来区分联合和类型断言,因为输出类型被推断为单一类型,而不是联合。
我们遇到了一个无法解决的 TS 错误,我想知道是否有人知道如何修复它。 TS 似乎在 combo.input
上推断出一个交集类型,这看起来很奇怪(联合类型对我来说更有意义)。
我在下面总结了一个例子。
我们最终只是使用了不同的方法,但我觉得应该有一种方法可以键入函数来修复错误。
const stringFunc = (input: string): string => input;
const numFunc = (input: number): number => input;
const stringCombo = { funct: stringFunc, input: 'hello' };
const numCombo = { funct: numFunc, input: 4 };
type Combo = typeof stringCombo | typeof numCombo;
const processCombo = (combo: Combo) => {
return combo.funct(combo.input);
// Argument of type 'string | number' is not assignable to parameter of type 'never'.
};
这并没有错,更多的是设计限制。 combo.funct
是函数的并集。这意味着它可以是接受 string
的函数或接受 number
的函数,但在调用时无法知道它是哪个。因此,调用 combo.funct
的唯一安全方法是使用可以满足两个函数签名的参数。在这种情况下,该类型将是 number & string
,它会减少到 never
(如果这些函数接受不同的对象类型,则可能有一个值同时满足这两种对象类型)
在这种特殊情况下,函数和参数实际上是相关的,但打字稿不跟踪这一点。它所能看到的是 combo.input
的类型(即 string | number
)不能作为函数联合的参数 combo.funct
.
您可以使用有区别的联合:
const stringFunc = (input: string): string => input;
const numFunc = (input: number): number => input;
const stringCombo = { funct: stringFunc, input: 'hello', type: "string" as const };
const numCombo = { funct: numFunc, input: 4 , type: "number" as const};
type Combo = typeof stringCombo | typeof numCombo;
const processCombo = (combo: Combo) => {
return combo.type === "string"?
combo.funct(combo.input):
combo.funct(combo.input);
};
或者因为在这种情况下我们显然比编译器了解更多,所以我们可以使用类型断言:
const processCombo = (combo: Combo) => {
return combo.funct(combo.input as never);
};
除了 Titian Cernicova-Dragomir 的回答之外, 您还可以将您的类型建模为泛型:
type FunTtoT<T> = (t: T) => T;
const stringFunc: FunTtoT<string> = (input: string): string => input;
const numFunc: FunTtoT<number> = (input: number): number => input;
type Combo<T extends string | number> = { funct: FunTtoT<T>, input: T };
const stringCombo = { funct: stringFunc, input: 'hello' };
const numCombo = { funct: numFunc, input: 4 };
function processCombo<T extends string | number>(combo: Combo<T>) {
return combo.funct(combo.input);
};
const s = processCombo(stringCombo); // inferred to string
const n = processCombo(numCombo); // inferred to number
我更喜欢这种方法来区分联合和类型断言,因为输出类型被推断为单一类型,而不是联合。