如何修复打字稿查找类型中的错误?

How to fix error in lookup type for typescript?

我的问题: 我的问题的一个最小示例是 (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 在上面的例子中不起作用,我该如何解决?

我的尝试:

My question: What is the error in the above code example and how can I fix it? It seems that the type guard result !== undefined does not work...

"fix" 的一种方法是 return undefined 始终如一,而不是 returning 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;
    }
}

"fix" 的另一种方法是使用这样的显式类型:

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;
    }
}

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

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.

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

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 enum