🎖️typeScrpt中如何禁止操作某些属性?

简介: 在 TypeScript 中,类型否定允许你创建一个明确排除某些属性的类型。通常情况下,我们定义类型来规定对象必须具备的属性。而类型否定,就是相反的操作:我们规定对象不能有哪些属性,你可以将它视为“保留属性”。

嗨,大家好!这里是道长王jj~ 🎩🧙‍♂️

在 TypeScript 中,类型否定允许你创建一个明确排除某些属性的类型。通常情况下,我们定义类型来规定对象必须具备的属性。而类型否定,就是相反的操作:我们规定对象不能有哪些属性,你可以将它视为“保留属性”。

让我们看一个例子。假设我们有一个通用的 createItem 函数,可以将新的项目插入到 NoSQL 数据库(比如 MongoDB、DynamoDB 等)中。NoSQL 数据库表没有预定义的列模式,这意味着项目及其所有属性都会按原样存储。然而,为了检索这些项目,我们需要至少定义一个属性作为主键(比如,在 DynamoDB 中,这是哈希键)。通常是一个整数或 UUID 形式的 ID,可能由数据库或应用程序定义。

function createItem<TItem extends object>(item: TItem): TItem {
   
  // 数据库设置 ID
  const newItem = db.insert(item);

  return newItem;
}

// 返回带有 id { id: "0d92b425efc9", name: "John", ... } 的对象
const user = createItem({
    name: "John", email: "john@doe.com" });

我们可以使用任何 JavaScript 对象来调用这个函数,并将它存储在我们的 NoSQL 数据库中。但是如果我们传递的对象包含 id 属性会发生什么?

// 会发生什么?
//> 会创建一个新项目吗?
//> 如果已经存在该项目,会覆盖吗?
const user = createItem({
    id: "0d92b425efc9", name: "John", email: "john@doe.com" });

当然,实际发生的情况取决于数据库的设置。可能会创建新项目,也可能会覆盖现有项目,或者如果我们不应该指定外部 ID,甚至可能会引发错误。当然,我们可以简单地在函数中检查 id 属性并自行引发错误来防止这种情况。

function createItem<TItem extends object>(item: TItem): TItem {
   
  if('id' in item) throw new Error("项目不得包含 ID");
  // 数据库设置 ID
  const newItem = db.insert(item);

  return newItem;
}

// 抛出错误
const user = createItem({
    id: "0d92b425efc9", name: "John", email: "john@doe.com" });

现在,让我们更进一步,使用 TypeScript 的泛型和类型来从一开始就防止这种情况发生。我们只是禁止项目包含 id 属性。

type ReservedKeys = {
   
  id: string;
}

function createItem<TItem extends object>(
  item: TItem extends ReservedKeys ? never : TItem
): TItem {
   
  if('id' in item) throw new Error("项目不得包含 ID");
  // 数据库设置 ID
  const newItem = db.insert(item);

  return newItem;
}

在这个示例中,我们定义了一个 ReservedKeys 类型,其中包含我们不希望出现在项目中的属性。在函数签名中,我们使用 TItem extends ReservedKeys 来检查泛型 TItem 是否是 ReservedKeys 类型的子集。如果是,我们将函数的参数类型设置为特殊值 never

让我们回到之前的例子。现在,当我们传递带有 ID 的对象时会发生什么?

// 会发生什么?
//> TypeScript 错误:类型 '{ id: string; name: string; email: string; }' 无法分配给类型 'never'
const user = createItem({
    id: "0d92b425efc9", name: "John", email: "john@doe.com" });

TypeScript 报错,指出我们传递给函数的对象与预期的类型不匹配。

当然,我们永远不应该仅仅依靠静态类型检查来避免这种错误。实际实现中的运行时检查也应该始终检查属性 id 是否存在。类型否定是一种在编译时捕获可能错误的语法糖,具有与实际实现相匹配的函数签名。


🎉 你觉得怎么样?这篇文章可以给你带来帮助吗?当你处于这个阶段时,你发现什么对你帮助最大?如果你有任何疑问或者想进一步讨论相关话题,请随时发表评论分享您的想法,让其他人从中受益。🚀✨

目录
相关文章
|
6天前
|
存储 安全 编译器
C/C++陷阱——临时变量的产生和特性
C/C++陷阱——临时变量的产生和特性
|
9月前
|
JavaScript
🎖️typeScrpt中如何返回正确的类型?
条件返回类型确实是 TypeScript 中非常有用的强大功能,它允许您根据参数的类型为函数指定不同的返回类型,从而实现更强的类型安全性。
54 0
|
前端开发
前端学习案例1-对象的禁止配置
前端学习案例1-对象的禁止配置
46 0
前端学习案例1-对象的禁止配置
|
前端开发
前端学习案例17-对象禁止配置
前端学习案例17-对象禁止配置
49 0
前端学习案例17-对象禁止配置
|
Python
禁止直接分配给多对多集的正面改用emails_for_help.set()
禁止直接分配给多对多集的正面改用emails_for_help.set()
|
JavaScript BI 数据库
巧用标志字段实现填报数据的暂存与锁定
<br>用户页面端数据录入时,由于数据的不确定性,通常会需要将数据暂存而不真正入库,类似草稿功能,等能确保数据准确时再进行数据入库操作,来乾学院看看如果简单的通过一个标志字段实现数据的暂存与锁定。<a href="http://c.
1098 0
|
安全 API Java
AtomicXFieldUpdater,属性原子修改的外部工具类
前言 最近在看资料的时候偶然间看到了AtomicLongFieldUpdater这个工具类,觉得新鲜就查阅了相关的资料,发现居然是jdk1.5就有的工具类,不禁感叹自己对Java的理解还是太浅了,于是在此整理一下该类的资料,作为知识储备。
1459 0