为什么将字符串的条件返回类型分配给数字时不会出现类型错误?

问题描述 投票:0回答:1

我想定义一个打字稿函数,其条件返回类型取决于参数的类型:使用 true 类型的参数调用它返回一个字符串,使用 false 类型的参数调用它返回一个数字。我想出了以下函数 foo() ,它几乎按预期工作:

  • 使用 true 调用它,会推断出正确的返回类型(字符串)
  • 用 false 调用它,会推断出正确的返回类型(数字)

但是当直接将函数调用分配给不兼容的类型时,不会抛出类型错误,这是为什么?

// generic function with conditional return-type TReturn that depends on TSomeArg
const foo = <
  TSomeArg extends boolean,
  TReturn = TSomeArg extends true ? string : number,
>(
  someArg: TSomeArg,
): TReturn => {
  // to return the conditional type TReturn, one needs to explictly assert it, since typescript will otherwise infer the union type: 'Some String'|1234
  return (someArg ? "Some String" : 1234) as unknown as TReturn;
};

// this works fine
const testOne = foo(true); // inferred string as expected: "const testOne: string"
//      ^?

const testTwo = foo(false); // inferred number as expected: "const testTwo: number"
//      ^?

const testThree: number = testOne; // throws Error as expected: "Type 'string' is not assignable to type 'number'."
const testFour: string = testTwo; // throws Error as expected: "Type 'number' is not assignable to type 'string'."

// BUT, here I would expect some type-errors
const testFive: number = foo(true); // unexpected: no type-error (string is inccorrectly accepted as a number)
const testSix: string = foo(false); // unexpected: no type-error (number is incorrectly accepted as a string)

// only when I explicitly define TSomeArg, then the type-errors are thrown as expected
const testSeven: number = foo<true>(true); // throws type-error as expected: "Type 'string' is not assignable to type 'number'."
const testEighth: string = foo<false>(false); // throws type-error as expected: "Type 'number' is not assignable to type 'string'."

ts-playground

相同的代码
typescript types type-inference conditional-types generic-function
1个回答
0
投票

正如所写,似乎没有任何理由为什么

foo
TReturn中的
generic
,因为最好的情况是
TReturn
被指定为
TSomeArg extends true ? string : number
,并且任何其他类型参数都会给你你不想要的行为。但这里的问题不是要避免不良行为,而是要理解为什么会发生这种情况。


主要原因是函数返回类型充当推理目标,如microsoft/TypeScript#16072中实现。当你写的时候

const testFive: number = foo(true);

您在

context
中调用 foo(true),其返回类型预计为
number
。这是
TReturn
的推理站点。仅当调用函数时推理失败时,才使用通用类型参数默认值。但是推理成功了,所以上面的调用相当于

const testFive: number = foo<true, number>(true);

你会得到你不喜欢的行为。

© www.soinside.com 2019 - 2024. All rights reserved.