microsoft / microsoft/TypeScript

Proposal: repurpose "is" operator for a narrowing version of "satisfies"

未关闭
#62,146 5 条评论 4 个 reaction 已指派 0 人 在 GitHub 查看

还没有人认领这个 Issue。

Awaiting More Feedback Suggestion
主要语言
Go
星标
111k
派生
14.3k
平均合并
2 天 4 小时
30 天内合并 PR
132

描述

### 🔍 Search Terms

satisfies with narrowing
narrowing literals
satisfias, satisfiesas, sassafras

### ✅ Viability Checklist

- [x] This wouldn't be a breaking change in existing TypeScript/JavaScript code
- [x] This wouldn't change the runtime behavior of existing JavaScript code
- [x] This could be implemented without emitting different JS based on the types of the expressions
- [x] This isn't a runtime feature (e.g. library functionality, non-ECMAScript syntax with JavaScript output, new syntax sugar for JS, etc.)
- [x] This isn't a request to add a new utility type: https://github.com/microsoft/TypeScript/wiki/No-New-Utility-Types
- [x] This feature would agree with the rest of our Design Goals: https://github.com/Microsoft/TypeScript/wiki/TypeScript-Design-Goals

### ⭐ Suggestion

A narrowing version of the `satisfies` operator

```typescript
type Animal = "cat" | "dog";
const animal = "cat" is Animal;
/// ^? = Animal
```

### 📃 Motivating Example

Consider an API where the return type is influenced by the input type. For example, this simplification of [Tanstack Form](https://tanstack.com/form/latest/docs/overview) (I'm not a contributor to it, but I'm developing something similar).

```typescript
function useForm(defaultValues: T): T {
return /*something*/;
}

const values = useForm({
animal: "cat"
});
```

The type inferred from animal here is `string`.

This works fine if animal is a text input in our form, but what if we want it to be an enumeration, e.g. ``, and also retain some compile-time typechecking? e.g. we want to prevent this

```typescript
values.animal = "red"
```

`satifies` will error if the initial value is not valid, but it doesn't narrow the type:

```typescript
// #1
const values = useForm({
animal: "cat" satisfies Animal
});
// typeof values["animal"] = string
```

`as` achieves the equivalent of narrowing here, but it masks some errors:

```typescript
// #2
const values = useForm({
animal: "red" as Animal // no error
});
```

I propose to repurpose the existing `is` keyword. Could use another keyword; bikeshed it later.

```typescript
const values = useForm({
animal: "cat" is Animal
});
```

This would produce a compiler error if the left hand side was not an Animal (like satifies), but additionally narrow the type to Animal.

### 💻 Use Cases

**What shortcomings exist with current approaches?**

A more natural flow of the code is disrupted; the field can't be declared inline.

**What workarounds are you using in the meantime?**

This one is okay, but somewhat disrupts the flow of reading top to bottom.

```typescript
// #3
const initialAnimal: Animal = "cat";
const values = useForm({
animal: initialAnimal,
plainString: "a",
plainNumber: 1
});
```

This one requires declaring the entire type separately. Also there may be many more type args than just the data shape. This is the case in Tanstack Form. You'd need `useForm`;

```typescript
// #4
type FormValues = {
animal: Animal
}
const values = useForm({
animal: "cat"
});
```

This is probably what I find myself reaching for, but as with `#4` requires declaring the entire type

```typescript
// #5
type FormValues = {
animal: Animal
plainString: string
plainNumber: number
}
const initialValues: FormValues = {
animal: "cat",
plainString: "",
plainNumber: 0
}
const values = useForm(initialValues);
```

贡献指南

打开贡献指南

从这里开始

  1. 先读完整个 Issue,再读项目的贡献指南。
  2. 在 Issue 下留言说明你要接手 —— 这能避免两个人做同样的事。
  3. Fork 仓库,在一个分支上完成修改。
  4. 提交 Pull Request,并在描述里引用这个 Issue 编号。

调研方向

未指定实现文件、测试或入口点。首先查看现有的 `satisfies` 运算符以及示例中描述的类型断言行为,然后确定 `is` 的一种缩窄形式如何适配编译器的类型系统设计。当提案具有已接受的设计,并且实现和测试范围已定义时,即视为完成。

由索引模型根据 Issue 内容生成。

评估

技术栈
typescript
领域
compilers
Issue 类型
功能
难度
5/5
预计耗时
一周以上
活跃度
停滞
描述清晰度
基本清楚
新手友好度
30/100

把新 issue 发到你的邮箱

精选适合新手参与的 GitHub issue 摘要。