sentencia if - Typescript: Cómo ramificar según el tipo
Tengo algo así:
interface A {
a1: string;
a2: number;
a3: boolean;
}
interface B {
b1: number;
b2: boolean;
b3: string;
}
function foo<K1 extends keyof A, K2 extends keyof B>(input: K1 | K2) {
if (input keyof A ) { // <--- THIS IS WRONG!
console.log('got A type');
} else {
console.log('got B type');
}
}
foo('a1');
foo('b2');
¿Cómo actualizo la declaración if para que ramifique correctamente según el tipo?
He intentado keyof, typeof, instanceof.... ninguno de los cuales es correcto.
Respuesta #1
Las interfaces no existen en tiempo de ejecución, son exclusivamente una construcción en tiempo de compilación. Por lo tanto, no hay forma de usar un tipo en una expresión, ya que el tipo no estaría presente al ejecutar el código.
Lo mejor que podemos hacer es crear un objeto que contenga todas las claves de la interfaz que está garantizado por el compilador que contiene todas las claves de la interfaz y solo las claves de la interfaz
Luego podemos usar este objeto en un guardia de tipo personalizado para ayudar al compilador a restringir el tipo de la clave.
Una solución general se vería algo así:
interface A {
a1: string;
a2: number;
a3?: boolean;
}
interface B {
b1: number;
b2: boolean;
b3: string;
}
// Factory function for key type-guards
function interfaceKeys<T>(keys: Record<keyof T, 0>) {
return function (o: PropertyKey): o is keyof T {
return o in keys;
}
}
// The objects here are compiler enforced to have all the keys and nothing but the keys of each interface
const isAkey = interfaceKeys<A>({ a1: 0, a2: 0, a3: 0 })
const isBkey = interfaceKeys<B>({ b1: 0, b2: 0, b3: 0 })
function foo<K1 extends keyof A, K2 extends keyof B>(input: K1 | K2) {
if (isAkey(input)) { // custom type guard usage
console.log('got A type');
input // is K1
} else {
console.log('got B type');
input // is K2
}
}
foo('a1');
foo('b2');
