如何修复typescript查找类型中的错误?

如何修复typescript查找类型中的错误?,typescript,dictionary,types,type-conversion,lookup,Typescript,Dictionary,Types,Type Conversion,Lookup,我的问题:我的问题的一个最小示例是: 枚举键{foo=foo,bar=bar} 函数getValue我看到变量结果的类型为{[K in A]?:B | undefined;}[A]。然而,我希望typescript能够自动将其缩减为B |未定义。可能我在或dict的类型声明中有错误,因此typescript无法减少查找类型。。。 当前夜间版本3.9.0-dev.20200224中也会出现此错误。 将typeguard更改为typeofresult!==未定义没有帮助。 我的问题:上面的代码示例中

我的问题:我的问题的一个最小示例是:

枚举键{foo=foo,bar=bar} 函数getValue我看到变量结果的类型为{[K in A]?:B | undefined;}[A]。然而,我希望typescript能够自动将其缩减为B |未定义。可能我在或dict的类型声明中有错误,因此typescript无法减少查找类型。。。 当前夜间版本3.9.0-dev.20200224中也会出现此错误。 将typeguard更改为typeofresult!==未定义没有帮助。 我的问题:上面的代码示例中的错误是什么?如何修复它?似乎类型保护结果!==未定义不起作用

解决此问题的一种方法是一致返回undefined,而不是返回null。下面的代码可以作为API使用,但正如@austraas正确地说的,它不能有效地将类型guard中的结果缩小到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;
    }
}

我的问题:上面的代码示例中的错误是什么?如何修复它?似乎类型保护结果!==未定义不起作用

解决此问题的一种方法是一致返回undefined,而不是返回null。下面的代码可以作为API使用,但正如@austraas正确地说的,它不能有效地将类型guard中的结果缩小到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;
    }
}

.

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

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

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

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
    }
}
此外,我建议始终使用常量枚举