索引到具有枚举索引的小元组会不正确地触发 TS2493

Indexing into a small tuple with an enum index improperly triggers TS2493

下面的代码是我正在尝试做的事情的要点

enum Foo {
    Foo0, Foo1, Foo2, Foo3, Foo4 // many more
}

function bar(foo: Foo) {
    const baz: [any, any] = [0,0];

    // Only Foo0 and Foo1 are valid to pass to bar
    if(foo > 2) throw RangeError();
    return baz[foo];
    // ^ Linter gives the following, even though foo can't be greater than 2:
    // TS2493 [ERROR]: Tuple type '[any, any]' of length '2' has no element at index '2'.
    // TS2493 [ERROR]: Tuple type '[any, any]' of length '2' has no element at index '3'.
    // TS2493 [ERROR]: Tuple type '[any, any]' of length '2' has no element at index '4'.
}

因为检查 foo 值的行,baz[foo] 永远不会大于 2。有什么办法可以让 Typescript 相信它不需要担心这个?

type predicate 可以帮忙

enum Foo {
    Foo0, Foo1, Foo2, Foo3, Foo4 // many more
}

function bar(foo: Foo) {
    const baz: [any, any] = [0,0];

    // Only Foo0 and Foo1 are valid to pass to bar
    if(!checkIsFoo0OrFoo1(foo)) throw RangeError();
    return baz[foo];
}

function checkIsFoo0OrFoo1(foo: Foo): foo is (Foo.Foo0 | Foo.Foo1) {
  return foo > 2;
}

因为enum键可以与任何值相关联,即它们不必是升序数字或从一个特定数字开始,而且编译器不提供具体值,所以似乎没有办法干净地处理这个。

我建议断言 foo 是一个数字并使用它(尽管这仍然有可能出错):

function bar(foo: Foo) {
    const baz: [any, any] = [0,0];

    const index = foo as number;
    if (index > 1) throw RangeError(); // if enum is 0-based (default)
        return baz[index];
}

一般来说,您不应将 Enum 用于此类目的。

只需对 foo 参数使用 0|1 索引联合类型

type Foo = 0|1

function bar(foo: Foo) {
    const baz: [any, any] = [0,0];
    return baz[foo];
}