我一直在写 TypeScript,但我并不理解它
我承认,我不太了解 TypeScript
前几天,我处理乐观更新的代码时遇到了一个 bug,于是向同事Filip求助。Filip 是一位 TypeScript 专家,他提到这个satisfies
关键字正是我正在寻找的解决方案的一部分。
Satisfies
这到底是什么?我以前怎么没听说过?我是说,我已经用 TypeScript 一段时间了,所以很惊讶自己竟然不知道。
不久之后,我偶然发现了 @yacineMTB 的这条推文,他是一位多产的喋喋不休者,也是X.com(又名 Twitter)的工程师:
比如,为什么我不能直接运行TypeScript文件?如果我需要初始化整个目录和项目,那么脚本语言还有什么意义呢?
我又一次开始疑惑,为什么我之前对 TypeScript 一无所知。为什么不能运行 TypeScript 文件?脚本语言和编译型语言之间有什么区别?
我突然意识到,我并不十分了解我几乎每天都在使用的语言的一些基本知识,而我正是用这种语言来创建诸如Open SaaS之类的东西的,Open SaaS 是一个免费的开源 SaaS 启动器。
所以我决定退一步,对这些话题进行一些调查。在本文中,我将与大家分享我学到的一些最重要的知识。
TypeScript 是什么类型的脚本?
你可能已经听说过 TypeScript 是 JavaScript 的“超集”。这意味着它是 JavaScript 之上的一个附加层,在这种情况下,它允许你为 JavaScript 添加静态类型。
就好像 TypeScript 是 JavaScript 的高级版一样。或者换句话说,如果 JavaScript 是特斯拉 Model 3 的基础款,那么 TypeScript 就是 Model X Plaid。呜呜呜。
但由于它是JavaScript 的超集,因此它的运行方式实际上与 JavaScript 本身不同。例如,JavaScript 是一种脚本语言,这意味着代码在执行过程中会被逐行解释。它被设计成可以在跨不同操作系统和硬件配置的 Web 浏览器中运行。这与 C 语言等低级语言不同,后者需要先编译成特定系统的机器码才能执行。
因此,JavaScript 无需先编译,而是由 JavaScript 引擎解释执行。而 TypeScript 则必须先转换(或“转编译”)成 JavaScript,才能由浏览器中的 JavaScript 引擎执行(或作为独立的 NodeJS 应用执行)。
所以这个过程看起来有点像这样:
→ Write TypeScript Code
→ “Transcompile” to JavaScript
→ Interpret JavaScript & Check for Errors
→ JavaScript Engine Compiles and Executes the Code
很有趣吧?
但是现在我们已经解决了一些理论问题,让我们继续讨论一些更实际的东西,比如 TypeScript 所熟知的东西:类型!
顺便一提…
我们正在Wasp努力创建最好的开源 React/NodeJS 框架,让您快速行动!
因此,我们提供了现成的全栈应用模板,例如使用 TypeScript 的 ToDo 应用。您只需安装 Wasp 即可:
curl -sSL https://get.wasp-lang.dev/installer.sh | sh
并运行:
wasp new -t todo-ts
您将获得一个具有 Auth 和端到端 TypeSafety 的全栈 ToDo 应用程序,开箱即用,帮助您学习 TypeScript,或者只是快速安全地开始构建某些东西 :)
玩转satisfies
还记得我向同事求助时,他的解决方案涉及到satisfies
关键词吗?为了更好地理解,我决定打开编辑器,尝试一些基本的例子,我发现这是我学到的最有用的东西。
首先,我们以 person 对象为例,将其类型化为 ,Record
可以接受一组PossibleKeys
和string
或number
作为值。看起来就像这样:
type PossibleKeys = "id" | "name" | "email" | "age";
const person: Record<PossibleKeys, string | number> = { }
我们为常量添加类型的方式person
称为类型注解。它直接位于变量名之后。
让我们开始向该person
对象添加键和值:
type PossibleKeys = "id" | "name" | "email" | "age";
const person: Record<PossibleKeys, string | number> = {
id: 12,
name: "Vinny",
email: "vince@wasp-lang.dev",
age: 37,
}
看起来很简单,对吧?
现在,让我们看看 TypeScript 如何推断属性的类型person
:
有趣的是,当我们将鼠标悬停在 上时email
,我们看到 TypeScript 告诉我们 email 是 astring
或 a的联合类型number
,尽管我们明确地将其定义为 a string
。
如果我们尝试在这个类型上使用某些方法,可能会产生一些意想不到的后果。例如,string
让我们尝试一下这个方法:split
我们收到一个错误,提示该方法对 类型 不起作用number
。这是正确的。但这很烦人,因为我们知道email
是一个字符串。
让我们satisfies
通过将类型移到常量定义的末尾来解决这个问题:
type PossibleKeys = "id" | "name" | "email" | "age";
const person = {
id: 12,
name: "Vinny",
email: "vince@wasp-lang.dev",
age: 37,
} satisfies Record<PossibleKeys, string | number>;
现在,当将鼠标悬停在该email
属性上时,我们将看到它被正确推断为string
:
太棒了!现在我们可以毫无问题地split
将其转换email
为字符串数组了。
这就是satisfies
真正的亮点。它让我们验证表达式的类型是否与某个类型匹配,同时推断出最窄的类型。
超额财产检查
但是我在使用时注意到的另一个奇怪的事情satisfies
是,如果我直接在变量上使用它而不是在中间变量上使用它,它的行为会有所不同,如下所示:
// Directly on object literal
const person = { } satisfies PersonType;
// Using on intermediate variable
const personIntermediate = person satisfies PersonType
具体来说,如果我向对象添加另一个person
类型中不存在的属性,比如isAdmin
,直接使用时会出错,但使用中间变量则不会出错:
- 直接使用
satisfies
- 使用
satisfies
中间变量
您可以看到,在示例 2 中,没有错误并且 person“满足” PersonType
,尽管在示例 1 中并非如此。
这是为什么?
嗯,这实际上与 JavaScript 的基本工作原理有关,而与satisfies
关键字无关。让我们来看看。
上述示例中发生的过程就是所谓的“多余属性检查”。
过多的属性检查实际上是规则的例外。TypeScript 使用所谓的“结构类型系统”。这只是一种奇特的说法,如果一个值具有所有预期的属性,它就会被使用。
因此,使用personIntermediate
上面的例子,TypeScript 不会抱怨它person
有一个额外的属性,isAdmin
而这个属性在 中并不存在PersonType
。它拥有所有其他必要的属性,例如id
、name
、email
和age
,因此 TypeScript 会以这种中间形式接受它。
但是,当我们像示例 1 中那样直接在变量上声明类型时,会收到 TypeScript 错误:“‘isAdmin’ 在‘PersonType’类型中不存在”。这就是过度属性检查在起作用,它的作用是帮助你避免犯一些愚蠢的错误。
记住这一点是很好的,因为这将帮助你避免意外的副作用。
例如,假设我们将人员类型更改为具有可选isAdmin
属性,如下所示:
type PersonType = {
id: number,
name: string,
isAdmin?: boolean, // 👈 Optional
}
person
如果我们意外地用isadmin
属性isAdmin
而不是直接声明类型来定义,会发生什么?
TypeScript 不会报错,因为person
实际上它满足所有必需的类型。该isAdmin
类型是可选的,并且不存在person
,但这没关系。你犯了一个简单的错误,现在尝试访问该isAdmin
属性,但它不起作用:
哎呀!让我们用类型注释来解决这个问题,我们直接声明类型:
很好。因为我们在第 58 行使用了直接类型注解,所以我们获得了 TypeScript 的多余属性检查的好处。
谢谢,TypeScript!🙏
如果您发现此内容有用,并且希望看到更多类似的内容,您可以在 GitHub 上为 Wasp 加星,从而轻松地帮助我们! 。
待续…
感谢您加入我的旅程的第一部分,以更好地了解我们每天使用的工具。
这将是一系列持续的文章,我将继续以更具探索性、更自由的方式分享我的学习心得。希望您觉得其中的某些部分有用或有趣。
告诉我你接下来想看什么!你喜欢这种风格吗?你会修改一些东西吗?添加或删除一些内容?或者你对最近学到的东西有什么看法或类似的故事吗?
如果是的话,请在评论中告诉我们,下次再见:)
文章来源:https://dev.to/wasp/ive-been-writing-typescript-without-understanding-it-5ef4