掌握 TypeScript 模板文字类型:提高代码安全性和表现力

掌握 typescript 模板文字类型:提高代码安全性和表现力

好吧,让我们进入使用模板文字类型在 typescript 中进行编译时元编程的迷人世界。这个强大的功能使我们能够创建一些非常酷的类型级魔法,使我们的代码更安全、更具表现力。

首先,模板文字类型到底是什么?它们是一种基于字符串文字操作和创建新类型的方法。这就像拥有一种适合您类型的迷你编程语言。很整洁,对吧?

让我们从一个简单的例子开始:

type greeting = `hello, ${t}!`;type result = greeting; // "hello, world!"

在这里,我们创建了一个类型,它接受一个字符串并将其包装在问候语中。 typescript 编译器在编译时计算出结果类型。不过,这只是表面现象。

我们可以使用模板文字类型来创建更复杂的转换。例如,假设我们要创建一个将snake_case 转换为camelcase 的类型:

type snaketocamel = s extends `${infer t}_${infer u}`  ? `${t}${capitalize<snaketocamel>}`  : s;type result = snaketocamel; // "helloworldtypescript"

此类型递归地转换输入字符串,将下划线后的每个部分大写。 infer 关键字在这里至关重要 – 它允许我们将字符串的一部分提取到新的类型变量中。

但是为什么停在那里呢?我们可以使用这些技术在我们的类型系统中构建整个领域特定语言(dsl)。想象一下创建一个类型安全的 sql 查询构建器:

type table = "users" | "posts" | "comments";type column = "id" | "name" | "email" | "content";type select = `select ${c} from ${t}`;type where = `where ${t}`;type query =   `${select} ${where}`;type userquery = query; // "select name, email from users where id = 1"

此设置确保我们仅从有效表中选择有效列,所有这些都在编译时进行检查。不会再出现因列名输入错误而导致的运行时错误!

我们可以通过实现更复杂的类型级计算来更进一步。让我们创建一个可以执行基本算术的类型:

此类型可以将两个表示为字符串的数字相加。实际的实现相当复杂,涉及很多条件类型和递归,但最终结果是纯粹的编译时魔法。

这些技术的一个实际应用是创建高级表单验证模式。我们可以定义一个类型来描述表单的形状并使用它来生成验证规则:

type form = {  name: string;  email: string;  age: number;};type validationrule = t extends string  ? "isstring"  : t extends number  ? "isnumber"  : never;type validationschema = {  [k in keyof t]: validationrule;};type formvalidation = validationschema;// { name: "isstring", email: "isstring", age: "isnumber" }

然后可以使用此模式生成运行时验证代码,确保我们的验证逻辑始终与我们的类型定义匹配。

模板文字类型还使我们能够创建更灵活的 api。我们可以使用它们通过适当的类型推断来实现方法链:

type chainable = {  set: (key: k, value: v) => chainable;  get: () => t;};declare function createchainable(): chainable;const result = createchainable()  .set("foo", 123)  .set("bar", "hello")  .get();// result type: { foo: number, bar: string }

这种模式允许我们逐步构建对象,类型系统会跟踪每一步累积的属性。

编译时元编程最强大的方面之一是能够基于现有类型生成新类型。我们可以使用它来创建实用程序类型,以有用的方式转换其他类型。例如,让我们创建一个类型,使对象的所有属性都是可选的,但仅限于第一级:

type shallowpartial = {  [p in keyof t]?: t[p] extends object ? t[p] : t[p] | undefined;};type user = {  name: string;  address: {    street: string;    city: string;  };};type partialuser = shallowpartial;// {//   name?: string | undefined;//   address?: {//     street: string;//     city: string;//   } | undefined;// }

此类型使顶级属性可选,但使嵌套对象保持不变。它是 typescript 内置 partial 类型的更细致的版本。

我们还可以使用模板文字类型来创建更具表现力的错误消息。我们可以引导开发人员找到确切的问题,而不是出现神秘的类型错误:

type assertequal = t extends u  ? u extends t    ? true    : `expected ${u}, but got ${t}`  : `expected ${u}, but got ${t}`;type test1 = assertequal; // truetype test2 = assertequal; // "expected "world", but got "hello""

这种技术在库开发中特别有用,向用户提供清晰的反馈至关重要。

另一个有趣的应用是创建类型安全的事件发射器。我们可以使用模板文字类型来确保事件名称及其相应的负载正确匹配:

type eventmap = {  "user:login": { userid: string };  "item:added": { itemid: number; quantity: number };};type eventname = keyof eventmap;class typedeventemitter<t extends record> {  emit(event: e, data: t[e]): void {    // implementation details omitted  }  on(event: e, callback: (data: t[e]) => void): void {    // implementation details omitted  }}const emitter = new typedeventemitter();emitter.emit("user:login", { userid: "123" }); // okemitter.emit("item:added", { itemid: 456, quantity: 2 }); // okemitter.emit("user:login", { itemid: 789 }); // type error!

此设置可确保我们始终发出并侦听具有正确负载类型的事件。

模板文字类型也可用于实现类型级状态机。这对于复杂工作流程或协议的建模非常有用:

type State = "idle" | "loading" | "success" | "error";type Event = "fetch" | "success" | "failure" | "reset";type Transition =  S extends "idle"    ? E extends "fetch"      ? "loading"      : S    : S extends "loading"    ? E extends "success"      ? "success"      : E extends "failure"      ? "error"      : S    : S extends "success" | "error"    ? E extends "reset"      ? "idle"      : S    : never;type Machine = {  state: S;  transition: (event: E) => Machine<Transition>;};declare function createMachine(initialState: S): Machine;const machine = createMachine("idle")  .transition("fetch")  .transition("success")  .transition("reset");type FinalState = typeof machine.state; // "idle"

这个状态机是完全类型安全的 – 它不会允许无效的转换,并且会准确地跟踪当前状态。

总之,typescript 中使用模板文字类型的编译时元编程开辟了一个充满可能性的世界。它使我们能够创建更具表现力、类型安全和自文档化的代码。我们可以更早地捕获错误,提供更好的开发人员体验,甚至可以根据类型生成代码。虽然这些技术可能很复杂,但它们为构建强大而灵活的系统提供了强大的工具。与任何高级功能一样,明智地使用它们很重要 – 有时更简单的解决方案更易于维护。但如果使用得当,编译时元编程可以显着提高 typescript 代码的质量和可靠性。

我们的创作

一定要看看我们的创作:

投资者中心 | 智能生活 | 时代与回声 | 令人费解的谜团 | 印度教 | 精英开发 | js学校

我们在媒体上

科技考拉洞察 | 时代与回响世界 | 投资者中央媒体 | 令人费解的谜团 | 科学与时代媒介 | 现代印度教

以上就是掌握 TypeScript 模板文字类型:提高代码安全性和表现力的详细内容,更多请关注创想鸟其它相关文章!

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 chuangxiangniao@163.com 举报,一经查实,本站将立刻删除。
发布者:程序猿,转转请注明出处:https://www.chuangxiangniao.com/p/1498702.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2025年12月19日 20:41:33
下一篇 2025年12月13日 02:10:30

相关推荐

  • 了解 Playwright:自动化 Web 测试的未来

    剧作家的定义 Playwright 是一个现代的开源测试框架,使开发人员能够以速度、可靠性和跨浏览器支持自动执行 Web 应用程序的端到端测试。它由 Microsoft 构建,解决了传统测试工具面临的许多挑战,为现代 Web 应用程序提供无缝自动化。 什么是剧作家? Playwright 是一个 N…

    2025年12月19日
    000
  • JS 中的三元运算符:您需要了解的一切

    什么是三元? 三元运算符是一个 javascript 运算符,自 2015 年 7 月起可跨浏览器使用。它是 if/else 语句的简写替代方案。该运算符广泛应用于 java、c、python 等不同的编程语言中,但本文的重点将放在 javascript 上。 让我们看看三元运算符的一般语法。 co…

    2025年12月19日
    000
  • JavaScript井号函数名:为什么我的WebView报错而Chrome正常?

    JavaScript井号(#)命名浏览器兼容性问题 在使用npm的pdf-dist包时,遇到浏览器兼容性问题。在WebView中,以井号(#)开头的函数名会出现”Unexpected token”的语法错误,而Chrome浏览器中没有问题。 解决方法: Android Web…

    2025年12月19日
    000
  • 使人才与业务目标保持一致:数据驱动的方法

    介绍 在快速发展的技术环境中,企业必须聘用不仅满足最低可行要求(MVR)而且还能通过机会领域为未来增长做出贡献的人才。在 TeamStation AI,我们采用数据驱动的方法来进行人才调整。本文探讨了我们如何使用数学模型使人才与业务目标保持一致,重点关注投资回报率和长期战略成功。 了解人才调整 最低…

    2025年12月19日
    000
  • VShell:生产发布工作流程

    本周,我准备将我的命令行工具 vshell 发布到生产环境。此版本将使用户能够直接通过 npm 安装和使用 vshell,而无需在本地克隆和构建项目。该工具使用 javascript 和 node.js 编写,将托管在 npm 上以便于分发。以下是我实现此版本所遵循的步骤的详细分解: 自动化构建过程…

    2025年12月19日
    000
  • React开发:Vite打包和zustand状态管理是最佳选择吗?

    React 生态圈中的打包和状态管理新技术 一位开发者抛出了一个问题,询问 React 社区最近是否有新的打包或状态管理技术值得关注。 打包技术 该开发者目前正在使用 Vite 作为构建工具,并打算抛弃 webpack。社区推荐了 Vite 社区提供的众多 React 模板,其中可以选择最简约的模板…

    2025年12月19日
    000
  • React开发:如何用Vite、React Router和Zustand构建高效应用?

    react 最新打造和状态管理技术 作为一名久经沙场的 React 开发者,最近重拾 React 已成为许多人的当务之急。随着技术的不断发展,了解当前社区的最佳实践至关重要。 打造:抛弃 Webpack,拥抱 Vite Vite 的部署生产能力已经得到验证,因此它已成为构建新项目的最佳选择之一。其快…

    2025年12月19日
    000
  • React开发新趋势:打包工具和状态管理方案该如何选择?

    React 新技术巡礼:打包与状态管理 作为一名长期使用 React 的开发人员,你回到这一领域时可能会面临新技术的选择。本文将探讨 React 生态系统中打包和状态管理领域的最新发展。 打包 你已经提到了 Vite,这是一种备受赞誉的替代品,以其出色的开发体验和生产就绪构建而闻名。在 Vite 社…

    2025年12月19日
    000
  • React开发新趋势:Vite打包和Zustand状态管理好用吗?

    react 社区的打包和状态管理新技术 提问者使用 React 已有四年经验,近期打算重新拾起 React 进行开发,希望了解社区内有哪些好用的打包和状态管理技术。以下是提问者提出的具体问题: 打包技术:是否推荐使用最新的 CLI 推荐?状态管理:在 Vite 环境下,有哪些推荐的替代方案? 回答:…

    2025年12月19日
    000
  • 使用 Cloudflare Workers 实施 Gmail 发送 – 开发指南

    这是使用 cloudflare workers 实施 gmail 发送系列的第 2 部分: 第 1 部分:设置 ✅第 2 部分:开发环境(当前)第 3 部分:实施(即将推出) 介绍 在第 1 部分中设置 gmail api 访问权限后,我们现在将为 cloudflare workers 配置开发环境…

    2025年12月19日
    000
  • Android WebView中井号开头函数名导致语法错误该如何解决?

    webview中命名规范与井号函数名处理 在使用javascript中,建议采用字母、数字、下划线和$组合的命名规范,且首字符不能为数字。然而,在引入pdf-dist (2.14)后,用户在android webview中遇到语法错误,提示井号开头的函数名语法错误。 经过验证,ai的回答不正确,私有…

    2025年12月19日
    000
  • 为什么document.write无法重载defer脚本?

    为什么使用 document.write 无法重载 defer 脚本 在给定的代码段中,在页面加载后,document.write 无法重载 defer 脚本 2.js 和 3.js。 根源在于异步加载的 defer 脚本和 document.write 之间的交互。defer 脚本会在文档的 re…

    2025年12月19日
    000
  • 如何提前通知Quartz定时任务的执行?

    quartz 任务调度中的提前通知设置 在任务调度中,您需要在特定任务开始前一定时间发送通知。为了实现这一目标,有几种方法可以在不修改前端代码的情况下实现。 创建附加 quartz 定时任务 您可以创建另一个 quartz 定时任务,其表达式配置为在原任务执行前执行。例如,如果原任务使用每天 10:…

    好文分享 2025年12月19日
    000
  • Quartz任务如何提前预知并通知即将执行的Cron任务?

    quartz如何预先通知即将到来的cron任务? 您正在使用quartz调度程序来根据cron表达式安排任务。现在,您希望在每次任务开始前一段时间(例如 1 天、一周或 15 分钟)发送通知。 当您不希望更改前端时,实现这一目标的好方法是: 创建第二个quartz定时任务:将第二个quartz定时任…

    2025年12月19日
    000
  • Angular’s Biggest Misconception: “It’s Not Worth Learning Due to Fewer Jobs”

    在选择前端框架时,对 Angular 的一个常见误解是学习它不值得,因为“没有足够的工作机会”。让我们揭穿这个神话并探索 Angular 在就业市场中的现实地位。 为什么会存在这种误解? 这种信念源于将 Angular 职位发布数量与 React 进行比较。在许多地区,React 职位的数量通常超过…

    2025年12月19日
    000
  • 使用 populateDropdown 简化您的下拉菜单管理

    让我们开始吧!假设您正在构建一个动态 web 应用程序,常见任务之一是根据各种数据源填充下拉菜单。如果没有简化的方法,您会发现自己编写重复且容易出错的代码,这对于维护来说可能是一场噩梦。这时,一个简单而强大的函数(如 populatedropdown)可以发挥作用。它消除了麻烦,让您的生活变得更加轻…

    2025年12月19日
    000
  • Vue 3中如何绕过createApp单次调用限制?

    如何在 vue 3 中多次调用 createapp? vue 3 中,createapp 只可调用一次。然而,在某些情况下,我们需要手动挂载组件。以下介绍两种解决此问题的方案: 场景一:手动挂载弹窗 // 使用 createapp 创建一个局部应用const localapp = createapp…

    2025年12月19日
    000
  • Vue3中createApp多次调用:如何解决单例模式下的多实例化难题?

    单例与多实例化之间的难题:vue3 的 createapp 多次调用 在 vue3 中,createapp 的官方文档明确阐明其“单例”性质,即应用程序中只能调用一次。然而,在某些场景下,开发人员可能会面临需要多次调用 createapp 的情况,这引发了技术上的难题。本文将探究如何解决这一难题。 …

    2025年12月19日
    000
  • Axios 与 Fetch:哪个最适合 HTTP 请求?

    在 javascript 中发出 http 请求的方法有很多,但最流行的两种是 axios 和本机 fetch() api。在这篇文章中,我们将比较和对比这两种方法,以确定哪一种更适合不同的场景。 http 请求的基本作用 http 请求是与 web 应用程序中的服务器和 api 进行通信的基础。 …

    2025年12月19日 好文分享
    000
  • React组件渲染完成后如何安全地操作DOM?

    react 中渲染生命周期 在 react 中,组件的生命周期包括以下阶段: componentwillmount(已废弃,使用 componentdidmount 代替)componentdidmountcomponentwillreceivepropsshouldcomponentupdatec…

    2025年12月19日
    000

发表回复

登录后才能评论
关注微信