Proxy property in setter has never type (with MRE)

Viewed 71

With TypeScript 4.5.4 (current latest), this code (see below or in TypeScript playground) is throwing error Type 'any' is not assignable to type 'never'.(2322) for the version 1,2,3,4 yet for version 5 and 6 no error is reported. If we remove one of the num prop or str, all the errors are gone.

Is there an explanation for this design?

const myObj = {
  num: -1,
  arr: [1, 2, 3],
  str: '',
};

const proxy = new Proxy(myObj, {
  set(target, prop: keyof typeof myObj, value) {
    /* none of these works */
    // Ver. 1
    if (prop in target) target[prop] = value;
    // Ver. 2
    target[prop] = value;
    // Ver. 3
    target[prop as keyof typeof myObj] = value;
    // Ver. 4
    switch (prop) {
      case 'num':
      case 'str':
        target[prop] = value;
        break;
    }

    /* while these works */
    // Ver. 5
    switch (prop) {
      case 'num':
        target[prop] = value;
        break;
      case 'str':
        target[prop] = value;
        break;
    }
    // Ver. 6
    switch (prop) {
      case 'num':
        target[prop] = value;
        break;
      default:
        target[prop] = value;
        break;
    }

    return true;
  },
});

console.log('proxy : ', proxy);
1 Answers

Summarized

Writing produces type intersection in TS.

Detailed

This is a copy of the answer from the official repo microsoft/TypeScript#47295, this is a functionality that "work as intended".

In most of your setups, the type of prop is not narrowed down from "num" | "str" | "arr"; since you're writing to target[prop] rather than reading from it, that produces an intersection (not a union) of all the possible types it could refer to. If there's no overlap, the intersection collapses to never, because there's no possible value that works for all of them.

This answer is created to close the question.

Related