Typescript 使用参数对函数进行类型推断

Typescript 使用参数对函数进行类型推断,typescript,Typescript,我最近一直在摆弄泛型类型,在编写一个函数时,我必须使用函数中的一个参数来确定返回类型 大致来说,以下是我希望能够做到的: const getString=()=>string'; 常量getNumber=()=>9999; 常量GetNumberRorString= < T扩展“number”|“string”, ReturnType扩展T扩展“数字”?编号:T扩展“字符串”?字符串:void >(which:T):ReturnType=>{ 开关(哪个){ 案件编号: 返回getNumber(

我最近一直在摆弄泛型类型,在编写一个函数时,我必须使用函数中的一个参数来确定返回类型

大致来说,以下是我希望能够做到的:

const getString=()=>string';
常量getNumber=()=>9999;
常量GetNumberRorString=
<
T扩展“number”|“string”,
ReturnType扩展T扩展“数字”?编号:T扩展“字符串”?字符串:void
>(which:T):ReturnType=>{
开关(哪个){
案件编号:
返回getNumber();
大小写“string”:
返回getString();
违约:
返回;
}
};
在Typescript平台上运行上述代码时,我遇到以下错误消息:

类型“number”不可分配给类型“ReturnType”。 “number”可分配给类型为“ReturnType”的约束,但“ReturnType”可以用约束“string | number”的不同子类型实例化。(2322)

类型“string”不可分配给类型“ReturnType”。 “string”可分配给“ReturnType”类型的约束,但“ReturnType”可以用约束“string | number”的不同子类型实例化。(2322)

类型“undefined”不可分配给类型“ReturnType”。 “ReturnType”可以用与“undefined”无关的任意类型实例化。(2322)


我能让这段代码运行而不出错的唯一方法是将返回语句键入
any
,但有没有其他方法可以做到这一点而不必诉诸于类型转换?

这是TypeScript中的已知限制;依赖于未指定泛型类型参数的条件类型的计算被延迟,编译器不知道如何验证值是否可分配给它们

getNumberString()
的实现中,泛型类型参数
T
未指定(它仅在调用
getNumberString()
时指定),因此返回类型
T扩展了“number”?编号:…
是这些延迟类型之一。因此,当您尝试返回任何特定值(如
return getNumber()
)时,编译器无法验证
number
是否可分配给该类型,您将得到一个错误

如果编译器可以使用类似于控制流分析的方法来理解
return getNumber()
只能在
T扩展'number'
时发生,那就太好了,但目前情况并非如此。请参阅,以获取实现对此支持的功能请求,以及关于为什么这不是一个容易解决的问题的讨论


因此,目前,使用泛型条件返回类型编写函数的唯一方法是使用(您称之为“类型转换”)或等效方法(如允许您放松实现签名的单个调用签名)

下面是编写函数的方法:

type NumOrStrReturnType<T> = 
  T extends 'number' ? number : 
  T extends 'string' ? string : 
  never;

const getNumberOrString =
    <T extends 'number' | 'string'>(which: T): NumOrStrReturnType<T> => {
        switch (which) {
            case 'number':
                return getNumber() as NumOrStrReturnType<T>;
            case 'string':
                return getString() as NumOrStrReturnType<T>;
            default:
                throw new Error("I DIDN'T EXPECT THAT");
        }
    };
编译器将
getNumberString2()
视为获取类型为
“number”
“string”
的参数,并返回类型为
number
string
的值,就好像它在查找类型为
NumOrStr
的对象中的属性一样。而实现实际上就是这样(通过getter)。这可以根据需要工作:

console.log(getNumberOrString2("number").toFixed(2)); // 9999.00
console.log(getNumberOrString2("string").toUpperCase()); // STRING
const sOrN = getNumberOrString2(Math.random() < 0.5 ? "string" : "number");
// const sOrN: string | number
console.log(getNumberOrString2(“number”).toFixed(2));//9999
console.log(GetNumberString2(“字符串”).toUpperCase());//一串
const sOrN=getNumberOrString2(Math.random()<0.5?“string”:“number”);
//常量排序:字符串|编号
为了从编译器获得类型安全性,是否值得跳过这些障碍?可能不会。但至少可以在这里做,我想这很好



你好!谢谢你的贡献。供日后参考。我刚刚提交了一个编辑,将您的屏幕截图更改为错误消息的实际文本内容。谢谢,下次我会记住这一点。
console.log(getNumberOrString2("number").toFixed(2)); // 9999.00
console.log(getNumberOrString2("string").toUpperCase()); // STRING
const sOrN = getNumberOrString2(Math.random() < 0.5 ? "string" : "number");
// const sOrN: string | number