为什么 return 类型的 `Overloaded Function(foo as any)` 不同于 `Return Type<typeof myOverloadedFunction>`?

Why is the return type of `myOverloadedFunction(foo as any)` different from `ReturnType<typeof myOverloadedFunction>`?

我有一个像这样的简单重载函数:

function myFunction(input: string): string
function myFunction(input: undefined): undefined
function myFunction(input: string | undefined): string | undefined
function myFunction(input: string | undefined): string | undefined {
    return input
}

此函数在正确输入的情况下按预期工作:

const result1 = myFunction('foo') // Inferred type of result1: string
const result2 = myFunction(undefined) // Inferred type of result2: undefined
const input3: string | undefined = 'foo'
const result3 = myFunction(input3) // Inferred type of result3: string | undefined

但是,当 input 被键入为 any 时,编译器假定正在使用第一个重载,即使 any 可以是 undefined

const result4 = myFunction(undefined as any) // Inferred type of result4: string

这让我感到惊讶(而且不正确!)。我希望 result4 被推断为 ReturnType<typeof myFunction>(即 string | undefined)。

这是怎么回事?这种行为的动机是什么?

我从 react-query 代码库中偶然发现了 this trick,并将其改编为针对此问题的 any 安全解决方案:

type NonOptional<T> = Exclude<T, undefined | null>

// Needs a better name than SafeMap, I'm open to suggestions
type SafeMap<TIn, TOut> = 0 extends 1 & TIn
  ? TOut | undefined
  : TIn extends NonOptional<TIn>
  ? NonOptional<TOut>
  : TIn extends undefined
  ? undefined
  : TOut | undefined;

function parseDate<T extends string | undefined>(arg: T): SafeMap<T, Date> {
  // Fake implementation to satisfy the compiler for the sake of this example
  return undefined as unknown as SafeMap<T, Date>
}

const anyArg: any = undefined
const stringArg: string = ''
const undefinedArg: undefined = undefined
const stringOrUndefinedArg: string | undefined = ''

const anyResult = parseDate(anyArg) // inferred type: `Date | undefined`
const stringResult = parseDate(stringArg) // inferred type: `Date`
const undefinedResult = parseDate(undefinedArg) // inferred type: `undefined`
const stringOrUndefinedResult = parseDate(stringOrUndefinedArg) // inferred type: `Date | undefined`
const _ = parseDate(42) // compilation error because 42 is not assignable to `string | undefined`

之所以可行,是因为 any 违反了类型的正常规则——您可能认为 1 & any1,但实际上是 any。所以 0 扩展 1 & any,但不扩展 1 & AnyTypeOtherThanAny