Typescript 缩小输入类型会导致扩大输出类型

Typescript 缩小输入类型会导致扩大输出类型,typescript,Typescript,这里是TypeScript中的一个函数选项。此函数获取一个值,对其应用映射函数,然后返回结果。如果值为null或未定义,则不调用映射函数并返回未定义 function mapA<T, U>(source: T, selector: (v: NonNullable<T>) => U) { return (source == null || source === undefined) ? undefined : selector(source!); } cons

这里是TypeScript中的一个函数选项。此函数获取一个值,对其应用映射函数,然后返回结果。如果值为null或未定义,则不调用映射函数并返回未定义

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
第二,为什么我需要在source!的末尾加一个感叹号!。控制流分析不应该知道此时它不是空的吗

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

这不是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,但我认为问题是没有一个推理站点可以让你。。。也许函数mapBsource:T,selector:v:NonNullable=>U&NonNullable:U | undefined{…}可以工作?我像你说的那样尝试了NonNullable,但无法工作。Ryan的答案是最好的,并且很容易理解。简短的版本是NonNullable对于U来说不是一个好的推理站点,因为它是一个条件类型别名,并且将被急切地解析为它的一个输出类型。它能够产生推理的唯一时间是,如果它是用另一个类型参数实例化的。
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