今天了解到:`satisfies` 是我最喜欢的 TypeScript 关键字。
`satisfies` is my favorite TypeScript keyword (2024)

原始链接: https://sjer.red/blog/2024-12-21/

TypeScript 的类型系统虽然强大,但并不总是能自动推断出最具体的类型。例如,一个简单的对象 `{ name: "Jerred" }`,其 `name` 的类型会被推断为 `string`,而不是字面量 `"Jerred"`。这可能会在函数需要精确的字面量类型时导致问题。 解决这个问题主要有两种方法:显式类型注解(例如 `const person1: { name: "Jerred" } = ...`)和 `satisfies` 关键字。`satisfies` 充当类型安全的断言,确保一个值*至少*可以赋值给指定的类型,同时仍然允许 TypeScript 基于该值本身推断出更具体的类型。 `satisfies` 在处理复杂类型和交集时表现出色,例如确保一个对象满足特定条件(例如 `isCool: true`),而无需冗长、预先定义的类型。它让 TypeScript 利用值的结构进行类型推断,从而产生更简洁、更易于维护的代码。

## TypeScript 的 `satisfies` 关键字:总结 这次 Hacker News 的讨论围绕 TypeScript 在 2024 年引入的关键字 `satisfies` 及其实际用途。虽然 TypeScript 学习曲线陡峭,但 `satisfies` 提供了一种强大的方式来强制类型约束,*而不会*改变底层类型。 一个关键用例是在 `switch` 语句中进行穷尽性检查,如果未处理所有可能的情况,则在编译时提供错误。它替代了像抛出错误或使用外部 linting 规则等技术。 讨论强调 `satisfies` 与 `as const` 不同;它在不进行类型转换的情况下验证类型,保留可变性并允许更灵活的类型定义。然而,一些开发者认为它过于复杂,更喜欢更简单的方法,尤其是在处理可选属性或过于复杂的类型签名时。 最终,`satisfies` 是寻求更高类型安全性和对代码更精确控制的高级 TypeScript 用户的一个有价值的工具,但它并非所有项目的必需品。这场辩论触及了一个更广泛的问题:开发者应该深入参与 TypeScript 的高级特性,还是优先考虑可读性和可维护性。
相关文章

原文

I’ve been doing a lot of work in TypeScript lately, and with that I’ve spent quite a bit of time learning more about its type system. TypeScript is a wonderfully advanced language though it has an unfortunately steep learning curve; in many ways it’s the complete opposite of Go.

One confusing thing about TypeScript is that it doesn’t always infer the most precise type possible. As an example:

// name is of type "Jerred"
const name = "Jerred";

// person1 is of type { name: string }
const person1 = {
  name: "Jerred",
};

// person2 is of type { readonly name: "Jerred" }
const person2 = {
  name: "Jerred",
} as const;

Why is the name of person1 of type string and not the literal "Jerred"? Because the object could be mutated to contain any other string.

What happens when I want to pass those objects to a function that requires name to be "Jerred"?

function handleJerred(name: "Jerred") {
  // do something
}

// these are okay
handleJerred(name);
handleJerred(person2.name);

handleJerred(person1.name);

Argument of type 'string' is not assignable to parameter of type '"Jerred"'.

As we’d expect, the types don’t match up. The most obvious way is to annotate the variable declaration with the expected type:

const person1: { name: "Jerred" } = {
  name: "Jerred",
};

// okay
handleJerred(person1.name);

We could also use the satisfies keyword. This keyword is a bit esoteric and not very common, but it comes in handy in some scenarios where you’d otherwise pull your hair out.

Here’s a quick example just to show the syntax:

const person1 = {
  name: "Jerred",
} satisfies { name: "Jerred" };

// okay
handleJerred(person1.name);

satisfies is an alternative to an explicit variable type annotation. It tells TypeScript that your assignment should be at least assignable to the provided type. It’s kind of like a type-safe way to cast values.

The benefit of satifies over an variable type annotation is that it lets TypeScript infer a more specific type based on the value provided. Consider this scenario:

type Person = {
  name: string;
  isCool: boolean;
};

function coolPeopleOnly(person: Person & { isCool: true }) {
  // only cool people can enter here
}

const person1: Person = {
  name: "Jerred",
  isCool: true,
};

// okay, so we need to say that `isCool` is true
coolPeopleOnly(person1);

Argument of type 'Person' is not assignable to parameter of type 'Person & { isCool: true; }'. Type 'Person' is not assignable to type '{ isCool: true; }'. Types of property 'isCool' are incompatible. Type 'boolean' is not assignable to type 'true'.

// and we also need to include the name field... const person2: { isCool: true } = { name: "Jerred",

Object literal may only specify known properties, and 'name' does not exist in type '{ isCool: true; }'.

isCool: true, }; const person3: { name: string; isCool: true } = { name: "Jerred", isCool: true, }; coolPeopleOnly(person3);

A simpler solution is to use satifies:

const person = {
  name: "Jerred",
  isCool: true,
} satisfies Person;

coolPeopleOnly(person);

TypeScript will ensure that your value is assignable to your type. The type of the assigned variable will be made based on the type of the value instead of the type provided to satisfies.

This really comes in handy when you want to ensure that TypeScript is being as specific as possible.

Read more:

联系我们 contact @ memedata.com