Búsqueda de sitios web

typescript - Mejor ayuda de verificación de tipos de TS


Tengo este código:

type Foo = {action: 'foo', label: '1'} | {action: 'foo', label: '2'} | {action: 'bar', label: '4'} | {action: "baz", label: "8"}

function action(action: Foo) {
  return action
}

action({action:"baz",label:"")

En este caso, cuando he puesto baz para la acción que quiero, pensé que, al poner la etiqueta, la sugerencia (autocompletar) simplemente me daría "8" como sugerencia. Pero me da todas las etiquetas, del 1 al 8, aunque no puede ser otra cosa que 8 si la acción es baz

¿Por qué es esto? ¿Y cómo puedo estructurar mis tipos para obtener el comportamiento esperado?

Respuesta #1

Este es un error conocido; vea microsoft/TypeScript#39438. Su tipo Foo es una unión discriminada, y el compilador debería tener suficiente información para reducir el tipo de la entrada de la función basándose en la propiedad action, pero no parece hacerlo a tiempo para modificar las sugerencias de autocompletado de IntelliSense. De todos modos, este error está listado como estando en la "lista de pendientes", lo que significa que probablemente no hay planes inmediatos para solucionarlo.


Como solución alternativa, podrías hacer que la función action() sea genérica así:

function action<T extends Foo["action"]>(action: Extract<Foo, { action: T }>) {
  return action
}

Estoy haciendo que T, el parámetro de tipo genérico, corresponda a la propiedad action. El parámetro de la función está tipado como Extract<Foo, {action: T}>, lo que usa el tipo de utilidad Extract<T, U> para decir "solo aceptar el/los miembro(s) de Foo cuya propiedad action es T".

Verifiquemos que se comporte como se desea. Todavía solo acepta valores válidos de Foo:

action({ action: "bar", label: "4" }); // okay
action({ action: "foo", label: Math.random() < 0.5 ? "1" : "2" }); // also okay
action({ action: "baz", label: "4" }) // error!
// -------------------> ~~~~~
// Type '"4"' is not assignable to type '"8"'

pero ahora IntelliSense es razonable y solo sugiere valores de la propiedad label compatibles con la propiedad action:

Enlace de Playground al código