函数“缺少return语句”,但具有所有路径的类型保护

mar*_*st2 5 typescript

我具有以下接口和类型(所有接口和类型都可以更改)

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
Run Code Online (Sandbox Code Playgroud)

我想做的是编写以下函数:

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'.

}
Run Code Online (Sandbox Code Playgroud)

我希望Rule会开始,因为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

Rya*_*ugh 6

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";
}
Run Code Online (Sandbox Code Playgroud)

什么是fn1()?这可能是"A" | "B" | undefined如果fn2()返回值比其他"alpha""beta",或者它可能是"A" | "B",如果这些是唯一返回值。好吧,让我们检查一下fn2()-它的返回类型是什么?取决于fn1()- 的类型,如果仅fn2返回,"alpha" | "beta"fn1返回"A" | "B""alpha" | "beta" | "gamma"如果undefined可能的返回值,则返回。

因此,要弄清楚fn1隐式返回的可及性,您必须进行多次“回合”推理,在其中根据另一个函数的类型来优化一个函数的类型,然后重复进行,希望您达到了一个固定点并不会无限递归。这是一个很大的不仅仅是做与隐性收益的语法执行单次更昂贵。

最简单的解决方法是添加一个throw

    } else if (...) {
       return ...;
    }
    throw new Error("Shouldn't be reachable");
}
Run Code Online (Sandbox Code Playgroud)

或者,如果您真的很喜欢代码覆盖,请if在最后一块中将条件重写为一个断言:

   } else {
       Debug.assert(x.kind === "B");
       return "C";
   }
Run Code Online (Sandbox Code Playgroud)

  • 这使得很多代码变得更糟,强制使用默认情况。如果我稍后向联合添加新类型,我希望编译器为我提供需要添加代码来处理新类型的所有位置。有时,不可能提供合理的默认值。几乎不可能提供适用于所有新类型的默认值。 (2认同)