使用枚举重载 TypeScript 函数

Posted

技术标签:

【中文标题】使用枚举重载 TypeScript 函数【英文标题】:TypeScript function overloading with enum 【发布时间】:2019-05-19 18:41:39 【问题描述】:

我在尝试使用 TypeScript 实现函数重载时遇到了一个小问题,其中一个枚举作为参数传递,第二个参数的类型取决于枚举。

例如:

如果枚举是FOO,那么第二个参数是string 类型 如果枚举是BAR,那么第二个参数是number 类型 如果枚举为BAZ,则没有第二个参数

我的代码如下,但不知何故 TypeScript 会抛出错误,因为即使我根据枚举检查第一个参数,intellisense 也不会缩小第二个参数的类型:fieldValue 始终是@987654328 @。

enum ViewName 
    FOO = 'foo',
    BAR = 'bar',
    BAZ = 'baz'


function myFunction(viewName: ViewName.FOO, stringValue: string);
function myFunction(viewName: ViewName.BAR, numberValue: number);
function myFunction(viewName: ViewName.BAZ);
function myFunction(viewName: ViewName, fieldValue?: string | number): void 

    if (viewName === ViewName.FOO) 
        fieldValue = fieldValue.reverse();
    

    if (viewName === ViewName.BAR) 
        fieldValue *= 2;
    

    if (viewName === ViewName.BAZ) 
        return console.log('No fieldvalue is supplied by BAZ.');
    

    console.log(fieldValue);

代码也可以在TypeScript Playground查看。

【问题讨论】:

我认为重载只适用于函数的调用者;在里面,它只是你提供的最后一个定义。 @jonrsharpe 你是对的:似乎函数重载在你调用它们时起作用(这样就可以有特定的参数组合),但是这种类型的缩小不会传递给函数本身:) 【参考方案1】:

Typescript 不会根据第一个参数的类型来缩小第二个参数的类型。这个功能只是没有在 typescript 中实现。

您可以向if 添加额外检查,让编译器缩小fieldValue 的类型

function myFunction(viewName: ViewName.FOO, stringValue: string);
function myFunction(viewName: ViewName.BAR, numberValue: number);
function myFunction(viewName: ViewName.BAZ);
function myFunction(viewName: ViewName, fieldValue?: string | number): void 

    if (viewName === ViewName.FOO && typeof fieldValue === "string") 
        fieldValue = fieldValue.reverse();
    
    else if (viewName === ViewName.BAR && typeof fieldValue === 'number') 
        fieldValue *= 2;
    

    console.log(fieldValue);

或者你可以只使用类型断言:

function myFunction(viewName: ViewName.FOO, stringValue: string);
function myFunction(viewName: ViewName.BAR, numberValue: number);
function myFunction(viewName: ViewName.BAZ);
function myFunction(viewName: ViewName, fieldValue?: string | number): void 

    if (viewName === ViewName.FOO) 
        fieldValue = (fieldValue as string).reverse();
    
    else if (viewName === ViewName.BAR) 
        fieldValue =  (fieldValue as number) * 2;
    

    console.log(fieldValue);

更大的变化是使用可区分联合,这将允许编译器以更预期的方式缩小参数的类型:

function myFunction(p:  viewName: ViewName.BAZ 
    |  viewName: ViewName.BAR, fieldValue: number 
    |  viewName: ViewName.FOO, fieldValue: string ): void 

    if (p.viewName === ViewName.FOO) 
        p.fieldValue =  p.fieldValue.reverse();
    
    else if (p.viewName === ViewName.BAR) 
        p.fieldValue *=  2;
    

    console.log(fieldValue);

【讨论】:

非常感谢您花时间回答我的问题:我不知道 TypeScript 不能根据函数重载推断/缩小其他参数的类型。这消除了我的疑虑:)

以上是关于使用枚举重载 TypeScript 函数的主要内容,如果未能解决你的问题,请参考以下文章

使用 `import type` 声明导入时,TypeScript 枚举不能用作值

如何区分 TypeScript 重载中的类型对象和数组?

LayaBox---TypeScript---类型兼容性

TypeScript类型

TypeScript 中的函数重载与使用联合类型

为啥 TypeScript 中没有重载的构造函数实现?