简体   繁体   English

通用函数中的联合类型

[英]Union type in generic function

I have code that looks like this: 我有看起来像这样的代码:

/** 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);
    }
}

I'm finding two problems with this set-up, however. 但是,我发现此设置有两个问题。 Both are related to the automatic deduction of the generic types in these utility functions. 两者都与这些实用程序功能中泛型类型的自动推论有关。

First, isSome does not seem to work as a typeguard: 首先, isSome似乎不能充当类型保护者:

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

It seems that the default deduction here is isSome<Optional<a>> , which quite frankly is wrong ( isSome<Optional<a>> should expect an argument of Optional<Optional<a>> , which is not what it's getting here). 似乎这里的默认推论是isSome<Optional<a>> ,坦率地说,这是错误的( isSome<Optional<a>>应该期望Optional<Optional<a>>的参数,这不是它在这里得到的结果) 。 If I'm explicit and use isSome<a> , then it works, but I decidedly do not want to do that. 如果我是明确的并且使用isSome<a> ,那么它可以工作,但是我绝对不想这样做。

Alternatively, isNone does work, which is why you see it used in outOfOptional : value has type a in the else block. 另外, isNone确实起作用,这就是为什么您看到它在outOfOptional使用的outOfOptionalvalueelse块中键入a

In addition, consider this usage of outOfOptional : 另外,请考虑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
        )
    );
}

Both haveOne and haveAnother are deduced to be a | None haveOnehaveAnother都被推论为a | None a | None rather than a , even though this leads to an error, and even though they could not be . a | None而不是a ,即使这会导致错误,即使他们不能 In effect, outOfOptional here seems to be treated as outOfOptional<Optional<a>> , except that's wrong, for the same reason isSome<Optional<a>> was wrong. 实际上,这里的outOfOptional似乎被视为outOfOptional<Optional<a>>outOfOptional<Optional<a>>是错误的,原因是isSome<Optional<a>>是错误的。 The first argument is Optional<a> , not Optional<a> | None 第一个参数是Optional<a> ,而不是Optional<a> | None Optional<a> | None or Optional<Optional<a>> as that deduction would imply. Optional<a> | NoneOptional<Optional<a>>因为这将暗示。 Given a first argument of Optional<a> , the generic type of outOfOptional must be a and definitely not Optional<a> . 给定Optional<a>的第一个参数, outOfOptional的泛型类型必须为a并且绝对不是Optional<a>

Why does TypeScript consider this a valid, and in fact more valid , deduction? 为什么TypeScript认为这是有效的,实际上更有效的推论? Is there anyway I can use a | None 反正我可以使用a | None a | None as an optional type, without having to explicitly indicate generic types in the related functions? a | None一个作为可选类型,而不必在相关函数中明确指出泛型?

Your intuition that this should be inferrable is correct, and in fact the current nightly build of TypeScript ( npm install typescript@next ) does infer the correct type now. 您的直觉是正确的,事实上,当前每夜构建的TypeScript( npm install typescript@next )现在都可以推断出正确的类型。

See the PR that fixed this https://github.com/Microsoft/TypeScript/pull/5895 and the originating bug https://github.com/Microsoft/TypeScript/issues/5861 请参阅修复此https://github.com/Microsoft/TypeScript/pull/5895的PR和原始错误https://github.com/Microsoft/TypeScript/issues/5861

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM