TypeScript: 通过一个小案例了解 ts 函数重载和类型保护

3,401 阅读2分钟

一个小需求

  • 我们想做一个这样的函数
    • 参数 number 默认值为 1
    • number 只能输入 1,2,3 三种类型

1、开始筹划

  • code
// 声明一个 number 的特殊类型,限制参数
type numberType = 0 | 1 | 2;

function test(a:numberType = 1){
    console.log(a)
}

test();
// 1

test(2);
// 2

什么是联合类型?

  • 认识和复习一下联合类型
  • 联合类型表示一个值可以是几种类型之一。 我们用竖线(|)分隔每个类型,所以number | string | boolean表示一个值可以是number,string,或boolean。

2、使用函数重载

function test(a?: numberType):number;

function test(a = 1):number | void {
    console.log(a)
}

test();
// 1

test(2)
// 2

函数重载的几个常见问题?

  • 所谓函数重载就是同一个函数,根据传递的参数不同,会有不同的表现形式。

JavaScript 模拟实现

function test(){ 
  if(arguments.length==0){ 
    console.log(a)("alert!");  
  } 
  else if(arguments.length==1){ 
    console.log(a)(arguments[0]) 
  } 
} 

test(); 
// alert!

test(2);
// 2
  • 为什么我会得到 Supplied parameters do not match any signature 的错误?(由于 JavaScript 没有函数重载)

  • 函数实现签名,它并不是重载的一部分:

function createLog(message: string): number;
function createLog(source: string, message?: string): number {
  return 0;
}

createLog('message'); // OK
createLog('source', 'message'); // ERROR: Supplied parameters do not match any signature

  • 当至少具有一个函数重载的签名时,只有重载是可见的。最后一个声明签名(也可以被称为签名的实现)对签名的形状并没有贡献,因此,要获得所需的行为,你需要添加额外的重载:
function createLog(message: string): number;
function createLog(source: string, message: string): number;
function createLog(source: string, message?: string): number {
  return 0;
}

3、或许可以使用类型保护

function isNumberType(type: number | numberType): type is numberType {
    return (number as numberType) !== undedined;
}

function test(number = 1){
    if(isNumberType(number)){
        console.log(number)
    }else{
        // 我们做更多的类型保护可以在格式错误的时候手动做一些用户提示的操作。
        console.error('error number!')
    }
}

test(1);
// 1

上面的类型保护的确看起来很臃肿,不过我们能做更多的事情。具体的类型保护官网文档讲得很清楚,大家可以再温习一下。

参考