🎖️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 是否存在。类型否定是一种在编译时捕获可能错误的语法糖,具有与实际实现相匹配的函数签名。


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

目录
相关文章
|
JavaScript
🎖️typeScrpt中如何返回正确的类型?
条件返回类型确实是 TypeScript 中非常有用的强大功能,它允许您根据参数的类型为函数指定不同的返回类型,从而实现更强的类型安全性。
83 0
|
6月前
|
前端开发 JavaScript
前端知识(十三)——JavaScript监听按键,禁止F12,禁止右键,禁止保存网页【Ctrl+s】等操作
前端知识(十三)——JavaScript监听按键,禁止F12,禁止右键,禁止保存网页【Ctrl+s】等操作
109 0
🎖️typeScrpt中如何使用条件类型和泛型?
我将通过一个可能对日常使用非常有帮助的代码示例更深入地介绍泛型。
72 1
|
PHP 数据库
织梦DEDECMS自动内链一个关键字对应多个链接随机调用的设置方法
利用dedecsm织梦自动内链的时候,可能会有一个关键字对应多个网站,随机调用网址的需求,比如(织梦自动内链)这个关键词一些文章内链链接到网站的首页,一些链接到文章页,但是织梦中原带的功能,一个关键词只能加一个网址,网上找了很多办法也没有找到可用的,还好米米素材网懂一点点php,哪就自己动手吧。下面是织梦自动内链一个关键字对应多个链接,随机调用这些链接的解决办法。
西门子S7-1200PLC变量表如何使用?如何声明、选用、显示、定义、更改变量?变量保持性如何设置?
在S7-1200 CPU的编程理念中,特别强调符号寻址的使用,在开始编写程序之前,用户应当为输入、输出、中间变量定义相应的符号名,也就是标签。具体步骤如下:
西门子S7-1200PLC变量表如何使用?如何声明、选用、显示、定义、更改变量?变量保持性如何设置?
还在写if?试试枚举策略
日常开发中或者代码优化过程中,一定会遇到不少的if语句,如果判断逻辑多了,会导致代码极其冗余,阅读性也会大打折扣,&quot;消灭&quot;if语句的方式有很多,也分不同的场景,本文将使用枚举策略的方式优化繁琐的if语句,你可以参考下文。
105 1
还在写if?试试枚举策略
|
Python
禁止直接分配给多对多集的正面改用emails_for_help.set()
禁止直接分配给多对多集的正面改用emails_for_help.set()
|
编译器 C++
如果不想使用编译器默认生成的函数,请明确拒绝它!
如果不想使用编译器默认生成的函数,请明确拒绝它!
151 0
|
Web App开发 前端开发
类选择器和所作用的标签一起写为什么不起作用? - CSDN博客
原文:类选择器和所作用的标签一起写为什么不起作用? - CSDN博客 HTML代码: css样式: 这不是将样式作用于circle类下的有current类的li标签吗?为什么不起作用? 原因: 选择器理解错误! 一般常用的选择器有标签选择器,类选择器,ID选择器,后代选择器等等。
1140 0