
TypeScript 的 satisfies 运算符已经推出一段时间了,但它似乎仍然是一个可以用来澄清的混乱来源。
可以把 satisfies 看作是将类型赋给值的另一种方式。
在我们深入研究之前,让我们回顾一下如何赋值类型。
首先,有一个不起眼的“冒号注解”(我们使用这个听起来有点像医学术语的名字,因为这个概念在 TS 文档中并没有真正给出一个名字)。
:表示“这个变量总是这个类型”:
const obj: Record<string, string> = {};obj.id = "123";
当你使用冒号注解时,你声明了变量是该类型。
这意味着你赋值给变量的东西必须是该类型:
// Type 'number' is not assignable to type 'string'.const str: string = 123;
给变量赋予的类型可能比你最初赋予的类型更宽。
let id: string | number = "123";if (typeof numericId !== "undefined") {id = numericId;}
当你想要有一个默认值,而这个默认值以后可能会被重新赋值时,这个方法非常有用。
但是冒号注释有一个缺点。
当使用冒号时,类型优先于值。
换句话说,如果你声明的类型比你想要的宽,你就被这个宽的类型困住了。
例如,在下面的代码片段中,你没有在routes对象上获得 autocomplete:
const routes: Record<string, {}> = {"/": {},"/users": {},"/admin/users": {},};// No error!routes.awdkjanwdkjn;
这就是  satisfies 被设计用来解决的问题。
这意味着它能推断出最窄的可能类型,而不是你指定的更宽的类型:
const routes = {"/": {},"/users": {},"/admin/users": {},} satisfies Record<string, {}>;// Property 'awdkjanwdkjn' does not exist on type// '{ "/": {}; "/users": {}; "/admin/users": {}; }'routes.awdkjanwdkjn;
satisfies  还能防止在配置对象中指定错误的内容。
因此,satisfies  和 冒号注解 同样安全。
const routes = {// Type 'null' is not assignable to type '{}'"/": null,} satisfies Record<string, {}>;
另一种为变量赋值的方式是使用 “ as ” 注解。
与  satisfies  和冒号注解不同,使用 “ as ” 注解可以让你对 TypeScript 说谎。
在这个例子中,你在IDE中看不到错误,但它会在运行时崩溃:
type User = {id: string;name: {first: string;last: string;};};const user = {} as User;// No error! But this will break at runtimeuser.name.first;
这些谎言有一些限制——你可以给对象添加属性,但是你不能在基本类型之间转换。
例如,你不能强制 TypeScript 将字符串转换为数字......
除非你用那个怪异的“as-as”:
// Conversion of type 'string' to type 'number'// may be a mistake because neither type// sufficiently overlaps with the other.const str = "my-string" as number;const str2 = "my-string" as unknown as number;
下面是  as  的合法用法,它用于将对象转换为尚未构造的已知类型:
type User = {id: string;name: string;};// The user hasn't been constructed yet, so we need// to use 'as' hereconst userToBeBuilt = {} as User;(["name", "id"] as const).forEach((key) => {// Assigning to a dynamic key!userToBeBuilt[key] = "default";});
警告:如果你使用  as  作为注解变量的默认方式,那几乎肯定是错误的!
下面的代码看起来很安全,但是一旦你给 User 类型添加了另一个属性, defaultUser 就过时了,而且它不会显示错误!
type User = {id: string;name: string;};const defaultUser = {id: "123",name: "Matt",} as User;
还有一种方法可以给变量赋类型:
什么都不加。
这不是打字错误!
TypeScript 在推断变量类型方面做得很好。
事实上,大多数情况下,你根本不需要输入变量:
const routes = {"/": {},"/users": {},"/admin/users": {},};// OK!routes["/"];// Property 'awdahwdbjhbawd' does not exist on type// { "/": {}; "/users": {}; "/admin/users": {}; }routes["awdahwdbjhbawd"];
总结一下,我们有四种方法来给变量赋类型:
-  冒号注解 
-  satisfies
-  as注解
-  不注解,让TS推断 
 由于有不同的方法来做类似的事情,它可能会让人们对何时使用何种方法感到有点困惑。
简单的用例是  satisfies  最适用的:
type User = {id: string;name: string;};const defaultUser = {id: "123",name: "Matt",} satisfies User;
但是大多数时候,当你想给变量赋一个类型时,你可能希望这个类型更宽。
如果这个例子使用的是 satisfies ,那么就不能把 numericId 赋给 id :
// colon annotationlet id: string | number = "123";if (typeof numericId !== "undefined") {id = numericId;}// satisfieslet id = "123" satisfies string | number;if (typeof numericId !== "undefined") {// Type 'number' is not assignable to type 'string'.id = numericId;}
经验法则是,你应该只在以下两种特定情况下使用satisfies:
-  你想要的是变量的精确类型,而不是宽泛类型。 
-  这个类型足够复杂,你需要确保你没有把它搞砸。 
欢迎关注公众号:文本魔术,了解更多


![基于SpringBoot开发的校刊投稿系统[附源码]](https://img-blog.csdnimg.cn/direct/54d86e3a1a29409f80cdad06c0c0bbc4.png)

![[word] word大小写快捷键是什么? #知识分享#学习方法#笔记](https://img-blog.csdnimg.cn/img_convert/aebb5cbcc027319d208baff296fdc85b.jpeg)















