SSF0SSF0
首页
前端
  • Node
  • Go
  • C#
  • MySql
  • Bash
  • Git
  • Docker
  • VuePress
  • CI/CD
  • 服务器
  • 网站
  • 学习资料
  • 软件
Timeline
Github
标签
分类
首页
前端
  • Node
  • Go
  • C#
  • MySql
  • Bash
  • Git
  • Docker
  • VuePress
  • CI/CD
  • 服务器
  • 网站
  • 学习资料
  • 软件
Timeline
Github
标签
分类
  • HTML

    • html1
    • html2
  • CSS

    • Flex 布局常见问题与解决方案
  • JavaScript

    • 数据类型及引用问题
    • 处理 Blob 类型文件下载问题总结
    • localStorage 与 sessionStorage 区别
    • JavaScript 中的 script 标签问题详解
    • JavaScript 中的`this`指向问题详解
    • SessionStorage踩坑记录:它真的能"只设置一次"吗?
    • 动态加载 JS 脚本方法对比
    • 浏览器页面关闭场景下的数据上报
  • es6

    • Promise
    • es6 模块导出方式全解析
  • Vue2

    • created VS mounted 发起异步请求
    • vue2-2
  • Vue3

    • Vite + Vue3 修改 element-plus 源码
    • Vue v-if 与 v-show
    • Vue3 ref 获取组件
    • Vue3 路由传参
    • 父子组件与组件里 Hooks 加载顺序
    • 第三方组件传入参数TS提示
    • Vue3 Props 在 Hooks 中的响应性处理
    • Vue Router 的两种历史模式及部署配置详解
    • 在Vue 3项目中顺利集成Tailwind CSS的完整指南
    • Vue 3 深度选择器:deep()完全指南
  • Electron

    • 快速构建 electron + vue3 项目
  • TS

    • TS 泛型
    • 记录模板使用断言的问题
    • type 与 interface
  • WebPack

    • Webpack 介绍
  • Vite

    • Vite CLI 常见命令
    • vite 与 webpack 比较
  • 项目工程

    • 前端代码风格
    • Vue3 项目规范
    • npm 镜像问题
    • 包管理工具
    • 使用 engines 限制开发环境依赖
    • 打包与shell交互指定模式
    • 使用 pnpm 构建 Monorepo 实战指南
    • pnpm 修改依赖源码打包报错
  • 记录一下小程序
  • 控制浏览器正确保存网站账号密码的技巧

泛型

什么是泛型

范型是编程语言中的一种特性,它允许我们定义函数、类或接口时使用类型参数,这些类型参数可以灵活地适应不同的数据类型。范型使得代码更加通用和灵活,能够处理多种数据类型,同时保持类型安全。

泛型语法

function identity<T>(arg: T): T {
  return arg;
}

多个类型参数:

function identity<T, U>(arg1: number, arg2: T, arg3: U): [number, T, U] {
  return [arg1, arg2, arg3];
}

使用示例:

let result = identity<string, number>(1, "hello", 2);
// result 的类型是 [number, string, number]
|| 或者
let result2 = identity(1, "hello", 2);
// result2 的类型是 [number, string, number]

<T, U> 是类型参数声明,可以理解为定义了两个类型变量。类型参数可以有多个,多个类型参数之间用逗号 , 隔开。

在 TypeScript 中,<T, U> 是类型参数,可以理解为占位符,用于在函数中表示类型。它们并不直接对应函数参数的位置,而是用于定义函数参数和返回值的类型关系。

类型参数的声明顺序(如 <T, U>)与函数参数的位置无关。类型参数是用来灵活定义类型的工具,可以在函数签名的任何位置使用。

比如在上面的例子中:

  • 虽然 T 在类型参数中排在第一位,但它被用于第二个参数 arg2

  • U 在类型参数中排在第二位,但它被用于第一个和第三个参数 arg1 和 arg3

泛型实际应用

分布式条件类型

分布式条件类型是指在条件类型中,当类型参数是一个联合类型时,条件类型会被应用到联合类型的每个元素上。

语法:

T extends U ? X : Y

使用示例:

type IsArray<T> = T extends Array<any> ? true : false;

const isArrayCheck1: IsArray<number[]> = true; // 正确,类型为 true
const isArrayCheck2: IsArray<string> = false; // 正确,类型为 false

// 实际应用:根据传入的参数类型不同执行不同的处理
function handleInput<T>(input: T): void {
  if (Array.isArray(input)) {
    console.log("处理数组:", input);
  } else {
    console.log("处理单个值:", input);
  }
}

// 使用示例
handleInput([1, 2, 3]); // 输出: 处理数组: [1, 2, 3]
handleInput("Hello"); // 输出: 处理单个值: Hello

自定义 Partial 类型

// 自定义 Partial 类型,使所有属性变为可选
type Partial<T> = {
  [P in keyof T]?: T[P];
};

interface User {
  name: string;
  age: number;
  email: string;
}

// 使用 Partial 进行可选属性的更新
function updateUser(id: number, updates: Partial<User>): void {
  // 假设在这里我们更新用户
  console.log(`更新用户 ID ${id} 的信息:`, updates);
}

// 实际应用:更新用户信息,只传入需要更新的属性
updateUser(1, { age: 30 }); // 只更新年龄
updateUser(2, { name: "Bob", email: "bob@example.com" }); // 更新姓名和邮箱

碰到的问题

写一个函数,传入的参数不能是 Ref 类型 ,但是传入的参数要是个对象。

import { ref, Ref, unref } from "vue";

type NotRef<T> = T extends Ref<any> ? never : T;

const ces = <T>(value: NotRef<T>) => {};

const a = ref<{ name: string }>({ name: "123" });

ces(unref(a)); // 正确
ces(a.value); // 正确
ces(a); // 类型“Ref<{ name: string; }>”的参数不能赋给类型“never”的参数。
ces([a, "123"]); // 正确

这里为什么 ces(a) 会报错,而 ces([a, "123"]) 不报错?

让我们逐步分析:

  1. ces(a) 的情况:

    • 传入的 a 是 Ref<{ name: string }> 类型
    • 经过 NotRef<T> 判断,因为它确实是 Ref 类型,所以返回 never
    • 因此报错
  2. ces([a, "123"]) 的情况:

    • 传入的是一个数组 [Ref<{ name: string }>, string]
    • 这个数组整体作为一个类型被传入 NotRef<T>
    • 数组类型本身不是 Ref 类型,所以 T extends Ref<any> 判断为 false
    • 因此返回原类型,可以正常使用

但是 const ces = <T>(value: NotRef<T>) => {}; 传入的参数是 [Ref<{ name: string }>, string] 类型,这里就要用到泛型约束。

泛型约束

泛型约束是指在定义泛型时,对类型参数进行约束,以确保传入的参数满足特定条件。

语法:

<T extends U>

使用示例:

import { ref, Ref, unref } from "vue";

type NotRef<T> = T extends Ref<any> ? never : T;

const ces = <T extends object>(value: T) => {};

const a = ref<{ name: string }>({ name: "123" });

ces(unref(a)); // 正确
ces(a.value); // 正确
ces(a); // 类型“Ref<{ name: string; }>”的参数不能赋给类型“never”的参数。
ces([a, "123"]); // 正确,🌟🌟🌟因为对象类型包括普通对象、数组、函数等,因为在 TypeScript 中,数组和函数都被视为对象的一种。
ces(() => {}); // 正确
ces(123); // 错误,因为 123 是 number 类型,不是对象类型
最后更新时间:
贡献者: 何风顺
下一页
记录模板使用断言的问题