javascript技巧

关注公众号 jb51net

关闭
首页 > 网络编程 > JavaScript > javascript技巧 > TypeScript确定返回类型

TypeScript使用函数重载确定返回类型的实现方法

作者:不知名靓仔

这篇文章主要介绍了TypeScript使用函数重载确定返回类型的实现方法,文中通过代码示例讲解的非常详细,对大家的学习或工作有一定的帮助,需要的朋友可以参考下

自定义一个hooks

import { useLocation } from 'react-router-dom';

// 定义 QueryParamsKey 类型为 string 或 Record<string, string>
type QueryParamsKey = string | Record<string, string>;

// 定义返回类型
type QueryParamsResult = Record<string, string>;

const useGetQueryParams = (key: QueryParamsKey): QueryParamsResult => {
  const location = useLocation();
  const queryParams = new URLSearchParams(location.search);
  
  // 初始化返回结果
  let values: QueryParamsResult = {};

  // 类型守卫,判断 key 是否为字符串
  if (typeof key === 'string') {
    values[key] = queryParams.get(key) || '';
  } else if (typeof key === 'object' && key !== null) {
    // 遍历对象中的每个键,并获取对应的查询参数
    Object.keys(key).forEach((k) => {
      // 使用 key 中的值作为查询参数的键
      values[k] = queryParams.get(key[k]) || '';
    });
  }
  
  return values;
};

export default useGetQueryParams;

问题:

使用 const {templateId} = useGetQueryParams(['templateId']) 提示类型“QueryParamsResultValues”上不存在属性“templateId”。

解释:

useGetQueryParams 函数的返回类型被定义为 QueryParamsResultValues,这是一个联合类型 string | Record<string, string>。当你调用 useGetQueryParams(['templateId']) 时,根据参数类型(在这里是一个数组),返回值应该是一个 Record<string, string>

问题是 TypeScript 无法在编译时确定函数的返回类型是 string 还是 Record<string, string>,因为它依赖于函数的运行时行为。所以,当你尝试解构返回值并访问 templateId 属性时,TypeScript 会抛出错误,因为它不确定返回的是不是一个对象。

解决

使用函数声明式函数重载来让 TypeScript 根据不同的参数类型来推断不同的返回类型

import { useLocation } from 'react-router';

type QueryParamsKeys = string | string[];
type QueryParamsResult = Record<string, string | null>;

// 函数重载声明
function useGetQueryParams(key: string): string | null;
function useGetQueryParams(keys: string[]): QueryParamsResult;

// 函数实现
function useGetQueryParams(keys: QueryParamsKeys): string | null | QueryParamsResult {
  const location = useLocation();
  const queryParams = new URLSearchParams(location.search);

  // 处理单个键的情况
  if (typeof keys === 'string') {
    return queryParams.get(keys);
  }
  // 处理键数组的情况
  else if (Array.isArray(keys)) {
    const values: QueryParamsResult = {};
    keys.forEach((k) => {
      values[k] = queryParams.get(k);
    });
    return values;
  }

  throw new Error('Invalid keys argument');
}

export default useGetQueryParams;

虽然我们有多个重载签名,但只有一个函数实现。在这个实现内部,我们处理所有可能的调用情况。当函数被调用时,TypeScript 编译器会根据提供的参数类型和重载签名来推断出哪个重载签名被使用,并据此检查返回类型的一致性。

因此,与普通的 JavaScript 不同,TypeScript 的函数重载不是真的在运行时提供多个不同的函数实现,而是在编译时对函数调用的类型进行检查和推断。实际的 JavaScript 代码中,仍然只有一个函数体

注意

在 TypeScript 中,你不能使用箭头函数来进行函数重载。函数重载是 TypeScript 的一项特性,它允许你为同一个函数提供多个函数类型定义。但是,这项特性仅限于传统的函数声明,不适用于箭头函数,因为箭头函数不能被命名。

// 函数声明,可以进行重载
function greet(name: string): string;
function greet(age: number): string;
function greet(single: boolean): string;
function greet(value: string | number | boolean): string {
  // 实际的实现逻辑
  return `Hello, ${value}`;
}

这是因为在 JavaScript 运行时,不存在函数重载的概念;它是 TypeScript 在类型系统层面提供的,用于在编译时检查和推断函数调用的类型。函数重载需要一系列具有相同名称的函数声明来实现,而箭头函数是匿名的,因此不能使用重载。

如果你希望在使用箭头函数的同时模拟函数重载的行为,你可以定义一个具有多个签名的类型,并将该类型赋给一个变量,然后将箭头函数赋给这个变量:

// 定义函数类型
type GreetFunction = {
  (name: string): string;
  (age: number): string;
  (single: boolean): string;
};

// 定义变量并赋予箭头函数,但实际上这不是函数重载
const greet: GreetFunction = (value: string | number | boolean): string => {
  // 实际的实现逻辑
  return `Hello, ${value}`;
};

上述方法并不是真正的函数重载,只是模拟函数重载的行为。尽管这不是真正的重载,但它仍然可以根据调用时传入的参数类型来返回不同的结果。

为什么箭头函数不支持重载:

为什么在 TypeScript 中使用函数声明进行重载:

到此这篇关于TypeScript使用函数重载确定返回类型的实现方法的文章就介绍到这了,更多相关TypeScript确定返回类型内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

您可能感兴趣的文章:
阅读全文