Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Typescript: How to branch based on type

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.

like image 1000
Marek Krzeminski Avatar asked Jan 22 '26 08:01

Marek Krzeminski


1 Answers

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');
like image 76
Titian Cernicova-Dragomir Avatar answered Jan 27 '26 01:01

Titian Cernicova-Dragomir



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!