microsoft / microsoft/TypeScript
Proposal: repurpose "is" operator for a narrowing version of "satisfies"
Nobody has claimed this yet.
- Dominant language
- Go
- Stars
- 111k
- Forks
- 14.3k
- Avg merge
- 2d 4h
- Merged PRs (30d)
- 132
Description
### 🔍 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);
```
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
No implementation files, tests, or entry points are named. Start by reviewing the existing `satisfies` operator and type-assertion behavior described in the examples, then determine how a narrowing form of `is` would fit the compiler's type-system design. Done means the proposal has an accepted design and a defined implementation and test scope.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- typescript
- Domain
- compilers
- Issue type
- Feature
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Stale
- Clarity
- Mostly clear
- Newbie friendliness
- 30/100