你知道下图中为什么定义了那么多个 ref 函数,它们的作用是什么?如果不清楚的话,阅读完本文的内容,也许你就懂了。
这是一个简单的 greet 函数,它接收一个字符串类型的参数,其返回值的类型也是字符串类型。
function greet(person: string): string {
return `Hello, ${person}!`;
}
当使用字符串阿宝哥作为参数调用 greet 函数时,将会返回 "Hello, 阿宝哥!"。那么现在问题来了,如果我们希望 greet 函数能同时支持输入用户列表并返回相应的问候列表那该咋办?
给你 3 秒钟的时间思考一下,你想到答案了么?其中一种方案是使用联合类型。
function greet(person: string | string[]): string | string[] {
if (typeof person === "string") {
return `Hello, ${person}!`;
} else if (Array.isArray(person)) {
return person.map((name) => `Hello, ${name}!`);
}
throw new Error("Unable to greet");
}
而另一种解决方案是使用函数重载,使用函数重载技术,我们需要定义重载签名和实现签名。
其中重载签名定义了函数中每个参数的类型和函数的返回值类型,但不包含函数体。一个函数可以有多个重载签名。
而实现签名的参数类型和返回值类型都需要使用更通用的类型,且还会包含实现该签名的函数体。一个函数只能含有一个实现签名。
结合了重载签名和实现签名之后,我们就实现了前面所说的功能:
// 重载签名
function greet(person: string): string;
function greet(persons: string[]): string[];
// 实现签名
function greet(person: unknown): unknown {
if (typeof person === 'string') {
return `Hello, ${person}!`;
} else if (Array.isArray(person)) {
return person.map(name => `Hello, ${name}!`);
}
throw new Error('Unable to greet');
}
在实际使用的过程中,只有重载签名才是可以调用的,调用函数之后的返回值就能够被推导出正确的类型。
需要注意的是,当 TypeScript 编译器处理函数重载时,它会查找重载列表,尝试使用第一个重载定义。如果匹配的话就立即返回。当使用实现签名对应类型的参数调用实现签名函数时将会出现错误。
除了重载普通函数之外,我们也可以对类中的方法进行重载。方法重载是指在同一个类中方法同名,参数不同(参数类型不同、参数个数不同或参数个数相同时参数的先后顺序不同),调用时根据实参的形式,选择与它匹配的方法执行操作的一种技术。
下面我们来看一个方法重载的例子:
class Calculator {
add(a: number, b: number): number;
add(a: string, b: string): string;
add(a: string, b: number): string;
add(a: number, b: string): string;
add(a: string | number, b: string | number) {
if (typeof a === 'string' || typeof b === 'string') {
return a.toString() + b.toString();
}
return a + b;
}
}
const calculator = new Calculator();
const result = calculator.add('Semlinker', ' Kakuqo');
阅读完本文之后,你应该就知道 Vue 3 响应式模块中的 ref 函数背后使用了什么技术。