1

Does type narrowing with the in operator only work for literals or am I missing something? Help me understand why this is happening please.

interface A {
    a: string;
}

interface B {
    b: number;
}

// This narrows the type correctly to A
function test(arg: A | B): string {
    if ('a' in arg) {
        return arg.a;
    }
    return arg.b.toFixed(2);
}

// This doesn't
function test2(arg: A | B): string {
    let a = 'a';
    if (a in arg) {
        return arg.a;
    }
    return arg.b.toFixed(2);
}

uloco
  • 2,283
  • 4
  • 22
  • 37

1 Answers1

3

Regarding to docs

For a n in x expression, where n is a string literal or string literal type and x is a union type, the “true” branch narrows to types which have an optional or required property n, and the “false” branch narrows to types which have an optional or missing property n.

So, I'd willing to bet it works only with literals

Workarounds

interface A {
    a: string;
}

interface B {
    b: number;
}

// This narrows the type correctly to A
function test(arg: A | B): string {
    if ('a' in arg) {
        return arg.a;
    }
    return arg.b.toFixed(2);
}

const isIn = <T, Prop extends string>(obj: T, prop: Prop): obj is T & Record<Prop, unknown> => prop in obj
const isIn2 = <T, Prop extends string>(obj: T, prop: Prop): obj is T & Record<Prop, unknown> =>
    Object.prototype.hasOwnProperty.call(obj, prop)

// This doesn't
function test2(arg: A | B): string {
    const a: 'a' = 'a' as 'a';
    if (isIn(arg, a) /** OR isIn2(arg, a) */) {
        return arg.a; // A        
    }


    return arg.b.toFixed(2);
}

  • but `a` is a string literal type, isn't it? – uloco May 04 '21 at 10:39
  • Looks like, they just don't support it yes. But then the docs are wrong or it's a bug: https://github.com/microsoft/TypeScript/issues/43284 – uloco May 04 '21 at 10:48
  • 1
    I think the docs are not full yet. I know they are working hard on docs, the page I provided seems deprecated. Also there is no new page for `in` typeguard, hence - hard to tell. From time to time I'm using infromation from deprecated pages because there is no other) – captain-yossarian from Ukraine May 04 '21 at 10:50