掌握 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 digit = '0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9';type adddigits =   // ... (implementation details omitted for brevity)type add =   // ... (implementation details omitted for brevity)type result = add; // "579"

登录后复制

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

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

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 模板文字类型:提高代码安全性和表现力的详细内容,更多请关注【创想鸟】其它相关文章!

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

发布者:PHP中文网,转转请注明出处:https://www.chuangxiangniao.com/p/2649123.html

(0)
上一篇 2025年3月7日 08:21:39
下一篇 2025年2月21日 16:34:06

AD推荐 黄金广告位招租... 更多推荐

相关推荐

  • 变更集中的 Nodejs util 模块用法

    您将在 changesets 源代码中的第 4 行找到导入内容 import { format } from “util”; 登录后复制 本文概述了 util 模块及其在变更集中的用法。 实用模块 util模块主要是为了支持node.js自…

    2025年3月7日 编程技术
    200
  • 如何用 JavaScript 在循环外部中断 for 循环?

    如何在 javascript 中从外部中断 for 循环的执行 如何在 for 循环之外中断其执行?for 循环是一种用于遍历数组或对象的循环语句。当需要在外部中断循环的执行时,可以通过以下方式实现: 内部中断:尝试通过设置一个条件变量(例…

    2025年3月7日
    200
  • 创建 CLI 来搭建扩展

    在之前的练习中,我们使用 typescript 构建了一个浏览器扩展。这涉及一系列步骤,包括创建 vite 项目并对其进行定制以满足浏览器扩展的特定要求。虽然该过程并不是特别漫长或复杂,但我们可以通过使用 node cli(命令行界面)实现…

    2025年3月7日
    200
  • 未定义与未定义

    首先,我们需要了解 javascript 代码执行过程,它由两个阶段组成:内存创建阶段和代码执行阶段。 “未定义”和“未定义”都与内存空间有关。 未定义 在内存创建阶段,变量和函数被存储为键值对。 javascript 将 undefine…

    2025年3月7日
    200
  • 如何快速稳定访问GitHub?

    稳定快速访问 github 对于日常开发人员来说,访问 github 十分重要,但有时,除了科学上网之外,在日常环境中打开 github 会遇到困难,严重影响工作效率。 针对这一问题,除了使用科学上网工具外,还有一些方法可以帮助你快速稳定地…

    2025年3月7日
    200
  • 如何快速稳定地访问GitHub?

    如何快速稳定地访问 github? github 是许多开发人员不可或缺的平台,但由于服务器位于国外,国内访问时经常会遇到网络不稳定的问题。除了使用科学上网工具外,还有其他方法可以快速稳定地访问 github。 修改 hosts 文件 可以…

    2025年3月7日
    200
  • 开发人员如何快速稳定地访问GitHub?

    如何快速稳定地访问 GitHub 对于开发人员来说,访问 GitHub 至关重要。但是,由于防火墙或网络问题,有时无法稳定访问 GitHub,这会严重影响工作效率。 以下介绍了一些无需科学上网即可快速稳定访问 GitHub 的方法: 手动修…

    2025年3月7日
    200
  • 每个开发人员都应该掌握提高生产力和发展的基本工具

    在快速发展的软件开发世界中,生产力和持续增长至关重要。开发人员选择的工具可以显着影响他们的效率、创造力和职业发展。每个开发人员都应该掌握以下五个基本工具,以在他们的技术中脱颖而出: 版本控制系统(例如 Git)版本控制系统是现代开发工作流程…

    2025年3月7日
    200
  • JavaScript中如何异步中断for循环的执行?

    如何在javascript中从外部中断for循环的执行? 在javascript单线程的环境中,同步for循环一旦开始执行,就无法通过内部变量从外部中断。不过,我们可以通过异步的方式来实现从外部中断for循环。 解决方案:异步for循环 使…

    2025年3月7日
    200
  • 如何通过异步编程中断JavaScript中的for循环?

    如何从外部中断 javascript 中的 for 循环执行? 在 javascript 中,当需要从外部中断 for 循环的执行时,可以使用异步编程的方法。这是因为 javascript 是一种单线程执行环境,这意味着同步 for 循环无…

    2025年3月7日
    200

发表回复

登录后才能评论