Skip to content

property accessor creates intersection type instead of union #31694

Closed
@simonhaenisch

Description

@simonhaenisch

TypeScript Version: 3.5.1 (also happens with @next)

Search Terms: ternary, ternary intersection/union, property accessor intersection/union

Code

interface FooBar {
  foo: string;
  bar: number;
}

const set = (foobar: FooBar, key: 'foo' | 'bar', value: string) => {
  foobar[key] = key === 'foo' ? value : Number(value);
};

or

class FooBar {
  foo?: string;
  bar?: number;

  set(key: 'foo' | 'bar', value: string) {
    this[key] = key === 'foo' ? value : Number(value);
  }
}

Expected behavior:

Works (it did up to version 3.4.5).

Actual behavior:

An intersection type is inferred for foobar[key] (or this[key]), however I think it should be a union type.

index.ts:7:3 - error TS2322: Type 'string | number' is not assignable to type 'string & number'.
  Type 'string' is not assignable to type 'string & number'.
    Type 'string' is not assignable to type 'number'.

7   foobar[key] = key === 'foo' ? value : Number(value);
    ~~~~~~~~~~~
index.ts:6:3 - error TS2322: Type 'string | number' is not assignable to type 'undefined'.
  Type 'string' is not assignable to type 'undefined'.

6   this[key] = key === 'foo' ? value : Number(value);
    ~~~~~~~~~

Playground Link:

Useless because this used to work up to version 3.4.5 (and the playground is stuck at version 3.3.3).

Related Issues:

Maybe #9239

If I use an if/else instead of the ternary operator, it works because it's easier to figure out the type of this[key]:

if (key === 'foo') {
  this[key] = value;
} else {
  this[key] = Number(value);
}

Metadata

Metadata

Assignees

No one assigned

    Labels

    Working as IntendedThe behavior described is the intended behavior; this is not a bug

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions