microsoft / microsoft/TypeScript

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

Abierto
#62,146 5 comentarios 4 reacciones 0 asignados Ver en GitHub

Nadie ha tomado este issue todavía.

Awaiting More Feedback Suggestion
Lenguaje dominante
Go
Estrellas
111k
Forks
14.3k
Merge medio
2 d 4 h
PR fusionados (30 d)
132

Descripción

🔍 Search Terms

satisfies with narrowing
narrowing literals
satisfias, satisfiesas, sassafras

✅ Viability Checklist
⭐ Suggestion

A narrowing version of the satisfies operator

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 (I'm not a contributor to it, but I'm developing something similar).

function useForm<T>(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. <select>, and also retain some compile-time typechecking? e.g. we want to prevent this

values.animal = "red"

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

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

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

// #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.

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.

// #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<FormValues, Blah, Blah, Blah, ...>;

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

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

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

Guía de contribución

Abrir la guía de contribución

Primeros pasos

  1. Lee el issue completo y luego la guía de contribución del proyecto.
  2. Comenta en el issue que vas a ocuparte — evita que dos personas hagan lo mismo.
  3. Haz un fork del repositorio y trabaja en una rama.
  4. Abre un pull request que haga referencia al número del issue.

Línea de trabajo

No se nombran archivos de implementación, pruebas ni puntos de entrada. Empieza revisando el operador satisfies existente y el comportamiento de las aserciones de tipo descrito en los ejemplos; después, determina cómo encajaría una forma de estrechamiento de is en el diseño del sistema de tipos del compilador. Se considera terminado cuando la propuesta tiene un diseño aceptado y un alcance definido para la implementación y las pruebas.

Escrito por el modelo de indexación a partir del texto del issue.

Evaluación

Stack tecnológico
typescript
Área
compilers
Tipo de issue
Nueva funcionalidad
Dificultad
5/5
Tiempo estimado
Más de una semana
Estado de actividad
Estancado
Claridad
Bastante claro
Aptitud para principiantes
30/100

Recibe los nuevos issues en tu correo

Un resumen breve de issues de GitHub para principiantes.