阅读视图

发现新文章,点击刷新页面。

客户端存储 - IndexedDB

客户端存储 IndexedDB:权威指南 IndexedDB 是很强大的低级 API,用户客户端存储大量结构化数据,包括文件或者blob。不像其他的 web 存储技术,IndexedDB 允许更加复杂

React入门:构建你的第一个应用

【引言】 突发奇想,打算搞个React的系列,从零基础到深入,简单聊聊咋用React,循序渐进,尽量讲得清楚点!希望大佬们多多指点,帮忙挑挑毛病,哈哈,感谢啦! 【系列文章大纲】 主题定位:面向具备前

Vue 响应式原理

Vue 的响应式原理是其核心特性之一,核心目标是实现「数据驱动视图」—— 当数据发生变化时,依赖该数据的视图会自动更新,无需手动操作 DOM。这一机制在 Vue 2 和 Vue 3 中实现方式有较大差

Vue3 特性标志

Vue3 通过特性标志(Feature Flags)为开发者提供了精细的构建控制能力,让你可以根据项目需求定制 Vue 的功能集,实现更小的包体积和更好的性能

TypeScript 函数重载入门:让你的函数签名更精确

一、什么是函数重载?

函数重载的核心思想是:对外声明多种调用方式,对内用一个统一的实现来处理。

一个完整的函数重载包含两个主要部分:

  1. 重载签名:定义了函数的各种调用形式,包括参数的类型、数量和返回值的类型。这些签名没有函数体。
  2. 实现签名:这是函数 唯一 的实现,它包含函数体。它的签名必须能够 兼容 所有重载签名。

示例: 一个 add 函数,既可以用于数字相加,也可以用于字符串拼接。

// 1. 重载签名 (Overload Signatures)
function add(x: number, y: number): number;
function add(x: string, y: string): string;

// 2. 实现签名 (Implementation Signature)
function add(x: any, y: any): any {
    // 3. 函数体实现
    if (typeof x === 'number' && typeof y === 'number') {
        return x + y;
    }
    if (typeof x === 'string' && typeof y === 'string') {
        return x + y;
    }
    throw new Error('Invalid arguments');
}

// 调用
const numSum = add(5, 10); // numSum 的类型被推断为 number
console.log(numSum); // 15
const strSum = add('Hello, ', 'World!'); // strSum 的类型被推断为 string
console.log(strSum); // Hello, World!

分析:

  • 外部可见性:当外部代码调用 add 函数时,TypeScript 会看到两个重载签名。它会根据你传入的参数,从上到下查找第一个匹配的签名。
  • 内部实现:实现签名 function add(x: any, y: any): any 对外部是不可见的,你不能用 (any, any) 的方式直接调用 add 函数(除非强制类型转换)。
  • 兼容性:实现签名必须涵盖所有重载签名。在这里,x: any, y: any 可以接受 (number, number)(string, string) 的情况。

二、重载的顺序

函数重载的顺序至关重要,因为 TypeScript 在解析调用时会 按顺序检查。一旦找到匹配的签名,它就会停止搜索。

  • 顺序一般是代码中从上而下的顺序。
  • 注:在有类型包含关系的情况下一般有小而大,例如:先number,再any

function move(p: Point): void; 
function move(p: any): void; 

// ... 实现 ...
function move(p: any): void {
  // ...
}

move({ x: 1, y: 2 }); // OK, p 的类型被正确推断为 Point

三、常见的几种函数重载的优化方案

1. 联合类型的应用

参数类型不同,但逻辑和返回类型相似

// 使用重载 (显得冗余)
function printId(id: number): void;
function printId(id: string): void;
function printId(id: number | string): void {
  console.log("Your ID is: " + id);
}

// 使用联合类型 (更简洁)
function printIdSimple(id: number | string): void {
  console.log("Your ID is: " + id);
}

2. 可选参数 或 默认参数

如果只是参数数量不同,可以使用 可选参数默认参数

// 使用重载
function greet(person: string): string;
function greet(person: string, greeting: string): string;
function greet(person: string, greeting?: string): string {
  return `${greeting || "Hello"}, ${person}!`;
}

// 使用可选参数 (更简洁)
function greetSimple(person: string, greeting?: string): string {
    return `${greeting || "Hello"}, ${person}!`;
}

3. 泛型

当函数的输入类型和输出类型之间存在一种模式或关联,但具体的类型是可变的,泛型 是最佳选择。

// 使用重载 (无法穷举所有类型)
function getFirstElement(arr: number[]): number | undefined;
function getFirstElement(arr: string[]): string | undefined;
function getFirstElement(arr: any[]): any | undefined {
    return arr[0];
}

// 使用泛型 (终极解决方案)
function getFirstElementGeneric<T>(arr: T[]): T | undefined {
    return arr[0];
}

const firstNum = getFirstElementGeneric<number>([1, 2, 3]); // 推断为 number
console.log(firstNum);
const firstStr = getFirstElementGeneric<string>(['a', 'b', 'c']); // 推断为 string
console.log(firstStr);

总结

如果你喜欢本教程,记得点赞+收藏!关注我获取更多JavaScript/TypeScript开发干货

❌