泛型函数中的联合类型

时间:2016-01-13 18:24:49

标签: generics typescript

我的代码如下:

/** explains the absence of a value */
export interface None {
    'is none because': string;
    // has spaces to reduce likelihood of a non-None having this member
}

/** Either a value or a reason why that value is missing. */
export type Optional<a> = a | None;

/** Possible value actually is a value */
export function isSome<a>(optValue: Optional<a>): optValue is a {
    return !('is none because' in optValue);
}

/** Possible value actually is absent */
export function isNone<a>(optValue: Optional<a>): optValue is None {
    return 'is none because' in optValue;
}

/** Consider optional value, require users to consider both possibilities */
export function outOfOptional<a, r>(value: Optional<a>, haveSome: (some: a) => r, haveNone: (reason: string) => r): r {
    if (isNone(value)) {
        return haveNone(value['is none because']);
    }
    else {
        return haveSome(value);
    }
}
但是,我发现这个设置存在两个问题。两者都与在这些效用函数中自动推导泛型类型有关。

首先,isSome似乎不能作为打字机使用:

if (isSome(value)) {
    // value here is still treated as a | None
}

这里的默认扣除似乎是isSome<Optional<a>>,这显然是错误的(isSome<Optional<a>>应该期待Optional<Optional<a>>的论证,这不是它在这里得到的)。如果我明确并使用isSome<a>,那么它可行,但我绝对不想这样做。

或者,isNone确实有效,这就是您在outOfOptional中看到它的原因:valuea块中有else类型。

此外,请考虑outOfOptional的使用情况:

export function outOfBothOptional<a, b, r>(
    one: Optional<a>, another: Optional<b>,
    haveBoth: (one: a, another: b) => r,
    haveFirst: (one: a) => r,
    haveSecond: (another: b) => r,
    haveNone: (none: string) => r
): r {
    return outOfOptional(
        one,
        haveOne => outOfOptional(
            another,
            haveAnother => haveBoth(haveOne, haveAnother),
            () => haveFirst(haveOne)
        ),
        () => outOfOptional(
            another,
            haveSecond,
            haveNone
        )
    );
}

haveOnehaveAnother推导为a | None而不是a,即使这会导致错误,即使他们也不能。实际上,此处的outOfOptional似乎被视为outOfOptional<Optional<a>>,除了错误之外,原因相同isSome<Optional<a>>错误。第一个参数是Optional<a>,而不是Optional<a> | NoneOptional<Optional<a>>,因为扣除意味着。鉴于Optional<a>的第一个参数,outOfOptional的泛型类型必须为a,绝对不是Optional<a>

为什么TypeScript认为这是有效的,实际上更有效,扣除?无论如何我可以使用a | None作为可选类型,而不必在相关函数中明确指出泛型类型吗?

1 个答案:

答案 0 :(得分:2)

你认为这应该是可以推断的直觉是正确的,事实上当前每晚的TypeScript版本(npm install typescript@next)确实推断出正确的类型。

查看修正此https://github.com/Microsoft/TypeScript/pull/5895的PR和原始错误https://github.com/Microsoft/TypeScript/issues/5861