Búsqueda de sitios web

Genéricos anidados en la definición de funciones en TypeScript


Estoy tratando de hacer manejadores tipo-seguros para acciones de Redux basándome en el tipo de acción. Por ejemplo, cualquier acción podría describirse como:

type ActionType<T extends string> = {
  type: T
};

Para una acción específica se puede tener:

type MyAction = ActionType<'hey' | 'there'>;

Ahora, me gustaría restringir una función manejadora para permitir solo 'hey' o 'there' como tipo. Finalmente, espero algo como esto:

handleAction<MyAction>('hey');

donde la definición de la función manejadora podría ser:

function handleAction<A extends ActionType<T>>(type: T){
...
}

Pero tengo un error de compilador de TypeScript:

TS2304: No se puede encontrar el nombre 'T'.

Entonces, tengo que modificar la definición de esta función manejadora de esta manera:

function handleAction<A extends ActionType<T>, T extends string>(type: T){
...
}

Funciona, pero se ve realmente feo:

handleAction<MyAction, 'hey' | 'there'>('hey');

Campo de Juegos TS

¿Cuál es una mejor manera de manejar esto?

Respuesta #1

Editar

Puedes usar una consulta de tipo para obtener el tipo de type:

function handleAction<A extends ActionType<string>>(type: A ['type']) {
}

handleAction<MyAction>('hey');

O puedes usar tipos condicionales en la 2.8 para extraer el parámetro genérico de ActionType (la 2.8 no estaba publicada al momento de escribir esto, pero se lanzará en marzo de 2018, puedes obtenerla mediante npm install -g typescript@next)

type ActionType<T extends string> = {
  type: T
};

type MyAction = ActionType<'hey' | 'there'>;


function handleAction<A extends ActionType<string>>(type: A extends ActionType<infer U> ? U : never) {
}

handleAction<MyAction>('hey');

Esta solución se basa en el comportamiento de inferencia del tipo condicional. ActionType<infer U> básicamente dice: Si a se extiende de ActionType de algún otro tipo U, dame el tipo U. Entonces U será el tipo literal de cadena que se pasó a ActionType en nuestro caso. Luego usamos U en la rama verdadera del tipo condicional y esto se convierte en el tipo final de nuestro tipo condicional. En este caso no nos importa la rama falsa, así que usamos never.

Artículos relacionados