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
变为typestring
,而在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
。我添加了一个您可能感兴趣的替代解决方案,它仍然使用重载,但也为函数接口使用泛型类型。