【问题标题】:narrowing input types causes widening of output type缩小输入类型导致扩大输出类型
【发布时间】:2018-05-22 16:49:42
【问题描述】:

这是 TypeScript 中的一个函数 Maybe 选项。该函数接受一个值,对其应用映射函数,然后返回结果。如果值为 null 或 undefined,则不调用映射函数并返回 Undefined。

function mapA<T, U>(source: T, selector: (v: NonNullable<T>) => U) {
    return (source == null || source === undefined) ? undefined : selector(source!);
}
const mapAResult = mapA(2, i => i * i); // Type is number | undefined

好的,所以现在我尝试通过将选择器的返回类型更改为NonNullable 来坚持映射函数永远不会返回 null 或 undefined。当我将鼠标悬停在mapBResult 上时,它说类型是{} | undefined。这对我来说似乎很奇怪。我想我是说该函数可以返回比上面的函数更少的可能值,但结果类型更广泛。不应该更少的可能输入导致更少的可能输出吗?

function mapB<T, U>(source: T, selector: (v: NonNullable<T>) => NonNullable<U>) {
    return (source == null || source === undefined) ? undefined : selector(source!);
}
const mapBResult = mapB(2, i => i * i); // Type is { } | undefined

其次,为什么要在source!的末尾加上一个感叹号。控制流分析不应该知道此时它不为空吗?

【问题讨论】:

    标签: typescript


    【解决方案1】:

    好的,所以现在我尝试通过将选择器的返回类型更改为 NonNullable 来坚持映射函数永远不会返回 null 或 undefined

    这不是NonNullable 所做的。

    你想要的是这个:

    function mapB<T, U extends object | string | number | boolean>(source: T | null | undefined, selector: (v: T) => U) {
        return (source == null || source === undefined) ? undefined : selector(source);
    }
    const mapBResult = mapB(2, i => i * i); // Type is number
    

    【讨论】:

    • 哇,真快。也许你可以解释一下为什么 NonNullable 没有达到我的预期?
    • 如果您愿意,您可以使用NonNullable,但我认为问题在于U 没有推理站点...也许function mapB&lt;T, U&gt;(source: T, selector: (v: NonNullable&lt;T&gt;) =&gt; U &amp; NonNullable&lt;U&gt;): U | undefined { ... } 会工作吗?
    • 我像你说的那样尝试了 NonNullable,但无法让它工作。 Ryan 的回答是最好的,而且很容易理解。
    • 简短的版本是NonNullable&lt;U&gt; 不是U 的一个好的推理站点,因为它是一个条件类型别名,并且会急切地解析为它的一种输出类型。唯一能够产生推理的情况是它是否用另一个类型参数实例化。
    猜你喜欢
    • 1970-01-01
    • 2017-09-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-06-01
    • 2016-01-07
    相关资源
    最近更新 更多