lunes, 22 de junio de 2026

Type predicates en Typescript

Dado el siguiente código:

const factoriaDeSimbolos = {
transposicion: (es_superior:boolean) =>
<g transform={`translate(15 ${es_superior ? '0': '58'})`}>
<Transposicion/>
</g>
}

enlaces.filter(
x =>
['diastema', 'fusion', 'transposicion'].includes(x.tipo)
).forEach(x => {
const indice_de_referencia = String(sequence.next())
dft[esSuperior(x.primer_casillero) ? 0 : 1].push(
<Insercion casillero={(x.primer_casillero+x.ultimo_casillero)/2} key={indice_de_referencia}>
{factoriaDeSimbolos[x.tipo](esSuperior(x.primer_casillero))}
</Insercion>
)
})

 

 Dentro del contexto del callback de forEach, quiero ser explícito en que el tipo de dato de x está modificado por el callback de la función filter en que la propiedad tipo pertenece a la enumeración de valores permitidos.

La forma idiomática en TypeScript es que el callback de filter sea un type predicate.

Supongamos:

type TipoEnlace =
| 'diastema'
| 'fusion'
| 'transposicion'
| 'otro';

interface Enlace {
tipo: TipoEnlace;
primer_casillero: number;
ultimo_casillero: number;
}

Podés definir:

type EnlaceConInsercion =
Enlace & {
tipo: 'diastema' | 'fusion' | 'transposicion';
};

function esEnlaceConInsercion(
enlace: Enlace
): enlace is EnlaceConInsercion {
return ['diastema', 'fusion', 'transposicion']
.includes(enlace.tipo);
}

y luego:

enlaces
.filter(esEnlaceConInsercion)
.forEach(x => {
// x.tipo es:
// 'diastema' | 'fusion' | 'transposicion'

const indice_de_referencia = String(sequence.next());

dft[esSuperior(x.primer_casillero) ? 0 : 1].push(
<Insercion
casillero={(x.primer_casillero + x.ultimo_casillero) / 2}
key={indice_de_referencia}
>
{factoriaDeSimbolos[x.tipo](esSuperior(x.primer_casillero))}
</Insercion>
);
});

Si no querés crear una función aparte, podés usar la sobrecarga de filter directamente:

enlaces
.filter(
(
x
): x is Enlace & {
tipo: 'diastema' | 'fusion' | 'transposicion';
} =>
['diastema', 'fusion', 'transposicion']
.includes(x.tipo)
)
.forEach(x => {
// x.tipo ya está refinado
});

Sin embargo, para código reutilizable y legible, la primera opción (esEnlaceConInsercion) suele ser bastante mejor. Además, TypeScript propagará automáticamente el refinamiento de tipos hasta el forEach.

No hay comentarios: