如何解决打字稿查找类型中的错误?

时间:2020-02-25 17:28:40

标签: typescript dictionary types type-conversion lookup

我的问题:我的问题的一个最小示例是(typescript play example with the code):

enum Keys { foo = "foo", bar = "bar" }

function getValue<A extends Keys, B>(dict: { [K in A]?: B }, key: A): B | null
{
    const result = dict[key]

    if (result !== undefined) {
        return result
    } else {
        return null
    }
}

Typescript对语句return result给出以下类型检查错误:

Type 'B | undefined' is not assignable to type 'B | null'.
  Type 'undefined' is not assignable to type 'B | null'.

我的问题:为什么上面的示例中的类型保护result !== undefined不起作用,该如何解决?

我的尝试

  • 在检查https://www.typescriptlang.org/play/index.html中的示例时,我看到变量result的类型为{ [K in A]?: B | undefined; }[A]。但是,我曾期望打字稿能够自动将其缩减为B | undefined。也许我在Adict的类型声明中有错误,所以打字稿无法减少查找类型...
  • 在当前的每晚版本3.9.0-dev.20200224中也会发生此错误。
  • 将打字机换成typeof(result) !== "undefined"并没有帮助。

2 个答案:

答案 0 :(得分:2)

目前,这似乎是TSC的错误或设计限制。它不能立即将{ [K in A]?: B | undefined; }[A]减少为B | undefined,因此您可以将结果强制转换为B | undefined或将Keys移出泛型

const enum Keys { foo = "foo", bar = "bar" }

function get<B>(
    dict: { [K in Keys]?: B },
    key: Keys
): B | null {
    const result = dict[key]

    if (result !== undefined) {
        return result
    } else {
        return null
    }
}

我也建议始终使用const枚举

答案 1 :(得分:1)

我的问题:上面的代码示例中有什么错误,我该如何解决?似乎类型保护结果!== undefined不起作用...

“修复”的一种方法是一致地返回undefined而不是返回null。以下内容可用作API,但正如@Austaras正确说的那样,它不能有效地将类型保护中的result缩小为B

function getValueOne<A extends Keys, B>(
    dict: { [K in A]?: B },
    key: A
): B | undefined {
    const result = dict[key]

    if (result !== undefined) {
        return result; // result is { [K in A]?: B | undefined; }[A]
    } else {
        return undefined;
    }
}

“修复”的另一种方法是使用这样的显式类型:

function getValueToo<A extends Keys, B>(
    dict: { [K in A]?: B },
    key: A
): B | null {
    const result: B | undefined = dict[key];

    if (result) {
        return result; // result is B
    } else {
        return null;
    }
}

第三种方法可能是我最喜欢的,因为它是三种方法中最通用的一种。我们更改返回类型。

function getValueThree<A extends Keys, B>(
    dict: { [K in A]?: B },
    key: A
): (typeof dict)[A] {
    const result = dict[key]

    if (result !== undefined) {
        return result;
    } else {
        return undefined;
    }
}

All three are in the playground