我有以下接口和类型(所有这些都可以更改)
interface Base {
type: string;
}
interface A extends Base {
type: "A";
field: string;
}
interface B extends Base {
type: "B";
query: string;
}
interface C extends Base {
type: "C";
equal: number;
}
type BaseExtensions = A | B | C;
interface BaseWrapper<R extends BaseExtensions> {
idType: string;
base: R;
}
interface And {
type: "AND";
rules: Array<BaseWrapper<any>>;
}
interface Or {
type: "OR";
rules: Array<BaseWrapper<any>>;
}
type Rule<R extends BaseExtensions> = BaseWrapper<R> | And | Or
我想做的是编写以下函数:
function doAThingBasedOnTheRuleType(rule: Rule<any>): Thing {
if (isAnd(rule)) {
return DoAndThing(rule);
}
if (isOr(rule)) {
return DoOrThing(rule);
}
if (isA(rule.base)) {
return DoAThing(rule);
}
if (isB(rule.base)) {
return DoBThing(rule);
}
if (isC(rule.Base)) {
return DoCThing(rule);
}
// error, [ts] Function lacks ending return statement and return type does not include 'undefined'.
}
我希望规则从And | Or | BaseWrapper<A> | BaseWrapper<B> | BaseWrapper<C>
开始,这应该逐一缩小。但是,我收到错误// error, [ts] Function lacks ending return statement and return type does not include 'undefined'.
1-为什么TS无法推断出类型? 2-我该如何解决?
我在TS 2.5.2上
答案 0 :(得分:3)
TypeScript关于隐式返回的规则是强制执行语法 - 在不知道所涉及的类型的情况下,需要在函数的所有可到达出口点都有一个return语句。
要弄清楚使用类型系统无法访问给定函数的隐式返回,需要多个“通过”,类型系统当前不执行此操作(出于性能/复杂性原因)。
例如,请考虑以下代码:
function fn1() {
const f = fn2();
if (f === "alpha") {
return "A";
} else if (f === "beta") {
return "B";
}
}
function fn2() {
const f = fn1();
if (f === "A") {
return "alpha";
} else if (f === "B") {
return "beta";
}
return "gamma";
}
fn1()
的类型是什么?如果"A" | "B" | undefined
返回fn2()
或"alpha"
以外的值,则可以是"beta"
,如果这些是唯一的返回值,则可以是"A" | "B"
。那么,让我们检查fn2()
- 它的返回类型是什么?如果fn1()
仅返回fn2
,则 取决于"alpha" | "beta"
- fn1
返回"A" | "B"
的类型,或返回{{1}如果"alpha" | "beta" | "gamma"
是可能的返回值。
因此,要弄清楚undefined
的隐式返回的可达性,你必须做多个“轮次”的推理,你可以根据另一个函数的类型细化一个函数的类型,然后重复,然后重复, 希望你达到一个固定点,不要无限递归。这比使用隐式返回的语法强制执行单次传递更加昂贵 lot 。
最简单的解决方法是简单地添加fn1
:
throw
或者,如果您真的进入代码覆盖范围,请将 } else if (...) {
return ...;
}
throw new Error("Shouldn't be reachable");
}
条件重写为最后一个块中的断言:
if
答案 1 :(得分:1)
如果您不会抛出任何错误,并且isC
是您的最后一个规则检查点,那么您是否无法删除该条件(因此始终会返回CThing)?
function doAThingBasedOnTheRuleType(rule: Rule<any>): Thing {
if (isAnd(rule)) {
return DoAndThing(rule);
}
if (isOr(rule)) {
return DoOrThing(rule);
}
if (isA(rule.base)) {
return DoAThing(rule);
}
if (isB(rule.base)) {
return DoBThing(rule);
}
return DoCThing(rule);
}