typescript - Marcar una función como un "guardia de tipo" natural en TS
Campo de Juegos TS
En TypeScript, el compilador no examina una función para determinar información de tipo.
function hasFoo(a: unknown): boolean {
return typeof a === 'object' && a !== null && 'foo' in a;
}
const x: unknown = null;
if (hasFoo(x)) {
console.log(x.foo);
// ^? const x: unknown
}
if (typeof x === 'object' && x !== null && 'foo' in x) {
console.log(x.foo) // x.foo is recognized
}
¿Es posible marcar hasFoo como un guardia de tipo "natural"? Un guardia de tipo "natural" es una función que le da al compilador de ts tanta información para la reducción de tipos como si la llamada a la función se expandiera. Por ejemplo, si hasFoo es un guardia de tipo "natural", entonces el compilador de ts sabría que x tiene una propiedad foo en el primer bloque if.
Estoy tratando de evitar definir un guardia de tipo como
interface FooHaver {
foo: unknown;
}
function hasFoo(a: unknown): a is FooHaver {
return typeof a === 'object' && a !== null && 'foo' in a;
}
porque es fácil cometer errores en el guardia de tipo. Además, dado que el compilador de ts ya puede resolver la información de tipo si se expande el cuerpo de hasFoo, no parece que debería ser demasiado difícil agregar más salvaguardas aquí.
Respuesta #1
Esta función ha sido solicitada múltiples veces, véase (#5101 y #10734 tangencialmente).
Se ha considerado demasiado complejo de implementar en el caso general. Hacerlo correctamente requiere combinar el análisis de control de flujo con algún tipo de análisis de flujo de datos.
Respuesta #2
No estoy al tanto de tal función, pero también la apreciaría.
Normalmente implemento guardianes de tipo como se muestra a continuación. Esto me proporciona una mayor seguridad de tipo, ya que producirá un error si FooHaver se cambia en el futuro de una manera que no satisfaga el guardián de tipo.
interface FooHaver {
foo: unknown;
}
function hasFoo(a: unknown): a is FooHaver {
// assert that 'foo' is a valid key of `FooHaver`
const k: keyof FooHaver = 'foo';
return typeof a === 'object' && a !== null && k in a;
}
