I have something like this:
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');
How do I update the if statement so that it branches correctly based on type?
i've tried keyof, typeof, instanceof .... none of which are correct.
Interfaces do not exist at runtime, they are exclusively a compile-time construct. So there is no way to use a type in an expression, since the type would not be there when running the code.
The best we can do is to create an object that contains all the keys of the interface that is compiler guaranteed to contain all keys of the interface and only the keys of the interface
We can then use this object in a custom type-guard to help the compiler narrow the type of the key.
A general solution would looks something like:
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');
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With