Typescript 使用泛型约束时,类型缩小未按预期工作

Typescript 使用泛型约束时,类型缩小未按预期工作,typescript,union-types,generic-constraints,type-narrowing,Typescript,Union Types,Generic Constraints,Type Narrowing,我有一种情况,泛型类型受到联合类型的约束,但我发现这样做并不会使类型缩小到预期的范围。下面的代码片段显示了发生的情况 function somefunc<T extends string | number>(input: T): T { if (typeof input === "string") { // expecting input to be of type "string" // but input becomes

我有一种情况,泛型类型受到联合类型的约束,但我发现这样做并不会使类型缩小到预期的范围。下面的代码片段显示了发生的情况

function somefunc<T extends string | number>(input: T): T {
  if (typeof input === "string") {
    // expecting input to be of type "string"
    // but input becomes of type T & "string"
    input
  } else {
    // expecting input to be of type "number"
    // but input becomes of type T extends string | number
    input
 }
}
我可能遗漏了一些东西,但问题是,我如何拥有基于联合的泛型约束,以及我所期望的类型缩小工作。在上述代码中,这将意味着,在
if
分支中,
input
变为type
string
,而在
else
分支中,它变为
number
(或者至少变为
T&number

**编辑**


我能够通过函数重载实现我想要的目标。我只是想知道如果使用泛型和条件类型可以实现同样的事情。

如果你想缩小到精确的类型,请考虑下一个例子:

函数somefunc(输入:number):number 函数somefunc(输入:字符串):字符串 函数somefunc(输入:string | number):string | number{ 如果(输入类型==“字符串”){ 返回输入//stirng }否则{ 返回输入//编号 } } 常数x=somefunc(10)

缺点:没有泛型)

如果你想缩小到精确类型,请考虑下一个例子:

函数somefunc(输入:number):number 函数somefunc(输入:字符串):字符串 函数somefunc(输入:string | number):string | number{ 如果(输入类型==“字符串”){ 返回输入//stirng }否则{ 返回输入//编号 } } 常数x=somefunc(10)
缺点:没有泛型)

中解释了它没有缩小的原因

正确缩小类型范围的常用方法:

type Result<T> = T extends string ? string : number;

function somefunc<T extends string | number>(input: T): Result<T> {
  const inputNarrowed: string | number = input;

  if (typeof inputNarrowed === "string") {
    inputNarrowed; // string
  } else {
    inputNarrowed; // number
  }

  return inputNarrowed as Result<T>;
}
type Result=T扩展字符串?字符串:数字;
函数somefunc(输入:T):结果{
const inputsrowned:string | number=输入;
if(输入类型缩小==“字符串”){
InputRowned;//字符串
}否则{
InputRowned;//数字
}
结果返回输入变窄;
}

重载+条件泛型的替代解决方案(我更喜欢)

type Result<T> = T extends string ? string : number;

function somefunc<T extends string | number>(input: T): Result<T>;
function somefunc(input: string | number) {
  if (typeof input === "string") {
    input; // string
  } else {
    input; // number
  }

  return input;
}

const str = somefunc("string"); // string
const num = somefunc(1); // number
type Result=T扩展字符串?字符串:数字;
函数somefunc(输入:T):结果;
函数somefunc(输入:字符串|编号){
如果(输入类型==“字符串”){
输入;//字符串
}否则{
输入;//数字
}
返回输入;
}
常量str=somefunc(“字符串”);//一串
常量num=somefunc(1);//数

中解释了未缩小的原因

正确缩小类型范围的常用方法:

type Result<T> = T extends string ? string : number;

function somefunc<T extends string | number>(input: T): Result<T> {
  const inputNarrowed: string | number = input;

  if (typeof inputNarrowed === "string") {
    inputNarrowed; // string
  } else {
    inputNarrowed; // number
  }

  return inputNarrowed as Result<T>;
}
type Result=T扩展字符串?字符串:数字;
函数somefunc(输入:T):结果{
const inputsrowned:string | number=输入;
if(输入类型缩小==“字符串”){
InputRowned;//字符串
}否则{
InputRowned;//数字
}
结果返回输入变窄;
}

重载+条件泛型的替代解决方案(我更喜欢)

type Result<T> = T extends string ? string : number;

function somefunc<T extends string | number>(input: T): Result<T>;
function somefunc(input: string | number) {
  if (typeof input === "string") {
    input; // string
  } else {
    input; // number
  }

  return input;
}

const str = somefunc("string"); // string
const num = somefunc(1); // number
type Result=T扩展字符串?字符串:数字;
函数somefunc(输入:T):结果;
函数somefunc(输入:字符串|编号){
如果(输入类型==“字符串”){
输入;//字符串
}否则{
输入;//数字
}
返回输入;
}
常量str=somefunc(“字符串”);//一串
常量num=somefunc(1);//数


这是因为对于泛型,您的
somefunc
方法将接受字符串或数字类型之上的任何内容。如果您知道
input
必须是string或number,您难道不能简单地执行
函数somefunc(input:string | number):string | number
?更新问题以提供更多信息如果else分支的类型为
t&number
,那么这仍然有效,类似于If分支的方式是
t&string
。但是现在,另一个是T extends string | numberth,因为对于泛型,您的
somefunc
方法将接受字符串或数字类型之上的任何内容。如果您知道
input
必须是string或number,您难道不能简单地执行
函数somefunc(input:string | number):string | number
?更新问题以提供更多信息如果else分支的类型为
t&number
,那么这仍然有效,类似于If分支的方式是
t&string
。但现在,另一个是T扩展字符串| numberYup。函数重载已经开始工作…想看看泛型和条件类型的组合是否可行:)顺便说一句,您可以调用
input.toString()
使其严格
string
,而不是
T&string
是的。函数重载已经开始工作…想看看泛型和条件类型的组合是否可行:)顺便说一句,您可以调用
input.toString()
使其严格
string
而不是
T&string
哈哈!这是邪恶的……但它是有效的!:)我不得不在返回表达式中做一些转换…例如
returninputResult应该是这样吗?是的,但是这不是由
输入缩小引起的。像
constfun=(输入:T)这样的简单函数:Result=>input
仍然要求您强制转换返回类型,因为返回类型是
Result
,而不是
T
,我添加了一个您可能感兴趣的替代解决方案,它仍然使用重载,但函数接口也使用泛型。哈哈!这是邪恶的……但它是有效的!:)我不得不在返回表达式中做一些转换…例如
returninputResult应该是这样吗?是的,但是这不是由
输入缩小引起的。像
constfun=(输入:T)这样的简单函数:Result=>input
仍然要求您强制转换返回类型,因为返回类型是
Result
,而不是
T
。我添加了一个您可能感兴趣的替代解决方案,它仍然使用重载,但也为函数接口使用泛型类型。