Typescript 为什么不’;条件类型是否在泛型函数中工作?

Typescript 为什么不’;条件类型是否在泛型函数中工作?,typescript,Typescript,为什么TypeScript不能使用泛型函数的类型参数约束来推断参数类型或返回类型 function isNum<T extends number>(x:T):T extends number?”Y”:”N”{ return “Y”; // <- error: type “Y” is not assignable to type ‘T extends number?”Y”:”N”’ } 函数isNum(x:T):T扩展数字“Y”:“N”{ 返回“Y”;//在需要泛型类型

为什么TypeScript不能使用泛型函数的类型参数约束来推断参数类型或返回类型

function isNum<T extends number>(x:T):T extends number?”Y”:”N”{
    return “Y”; // <- error: type “Y” is not assignable to type ‘T extends number?”Y”:”N”’
}
函数isNum(x:T):T扩展数字“Y”:“N”{

返回“Y”;//在需要泛型类型的地方赋值通常不起作用,typescript假定该值不兼容。这是因为当我们有一个泛型类型时,该类型表示
T
的任何可能的子类型

现在在这种情况下,很明显
T
将始终是
“Y”
,因为
T
上已经有一个约束,但typescript不会试图推断出这一点。更明显的情况是行不通的,因为typescript在这种情况下根本不会做任何分析:

function isNum<T extends number>(x: T): T extends number ? "Y" : "Y" {
    return "Y"; // still an error 
}
函数isNum(x:T):T扩展数字“Y”:“Y”{
返回“Y”;//仍然是错误
}
唯一的解决方案是使用类型断言:

function isNum<T extends number>(x: T): T extends number ? "Y" : "N" {
    return "Y" as any;
}
函数isNum(x:T):T扩展数字“Y”:“N”{
如有,返回“Y”;
}
编辑

正如@jcalz所指出的,另一个非常好的选择是使用多个重载(或者更具体地说是使用条件类型的公共重载,以及不使用条件类型的实现重载)

函数isNum(x:T):T扩展数字“Y”:“N”
函数isNum(x:number):“Y”|“N”{
返回“Y”;
}

不,Typescript还不支持条件返回类型。对于您的情况,您可以做以下几件事:

返回类型作为枚举
enum YesNo{
Y='Y',
N='N'
}
函数isNum(x:T):是否{
将x作为数字的任意实例返回?YesNo.Y:YesNo.N;
}
严格返回型
函数isNum(x:T):'Y'|'N'{
将x作为数字“Y”:“N”的任何实例返回;
}
如果希望返回类型作为特定类型
接口编号扩展编号{
...
}
接口编号扩展了编号{
...
}
函数isNum(x:T):一个数{
返回x;
}

注意:上面的接口也可以是类。

我想知道跟踪条件类型可分配性的痛苦是否有一个好的GitHub问题。无论如何,通常在这些情况下,我使用一个重载,其中调用签名具有条件类型,而实现签名具有并集。这至少可以实现是的,这也是一个很好的选择,我会加上它,当我写答案的时候我没有想到,因为一些原因,我看,它似乎是为了解决这个问题,但我不知道什么时候它会成为语言。
function isNum<T extends number>(x: T): T extends number ? "Y" : "N"
function isNum(x: number): "Y" | "N" {
    return "Y";
}
enum YesNo {
  Y= 'Y',
  N= 'N'
}
function isNum<T extends Number>(x:T) : YesNo {
  return x as any instanceof Number ? YesNo.Y : YesNo.N;
}
function isNum<T extends Number>(x:T) : 'Y' | 'N' {
  return x as any instanceof Number ? 'Y' : 'N';
}
interface ANumber extends Number {
  ...
}
interface BNumber extends Number {
  ...
}
function isNum<T extends Number>(x:T) : ANumber | BNumber {
  return x;
}