Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Proxy property in setter has never type #47295

Closed
PabloLION opened this issue Jan 3, 2022 · 4 comments
Closed

Proxy property in setter has never type #47295

PabloLION opened this issue Jan 3, 2022 · 4 comments
Labels
Working as Intended The behavior described is the intended behavior; this is not a bug

Comments

@PabloLION
Copy link

Bug Report

🔎 Search Terms

  • Proxy property in setter has never type
  • Type 'any' is not assignable to type 'never'.(2322)
  • Typing Proxy Constructor Proxy Handler
  • Typing ProxyConstructor
  • Typing ProxyHandler

🕗 Version & Regression Information

  • This is a crash (misbehavior)

⏯ Playground Link

Playground link with relevant code

💻 Code

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);

🙁 Actual behavior

With TypeScript 4.5.4 (current latest) and currently Nightly version, this code 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?

Also asked on stack overflow

🙂 Expected behavior

We can use all of version 1,2,3,4 without having this TS2322 error.

@fatcerberus
Copy link

Is there an explanation for this design?

Yes. See #30769. 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.

@beepeep
Copy link

beepeep commented Jan 3, 2022

Bug Report

🔎 Search Terms

  • Proxy property in setter has never type
  • Type 'any' is not assignable to type 'never'.(2322)
  • Typing Proxy Constructor Proxy Handler
  • Typing ProxyConstructor
  • Typing ProxyHandler

🕗 Version & Regression Information

  • This is a crash (misbehavior)

⏯ Playground Link

Playground link with relevant code

💻 Code

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);

🙁 Actual behavior

With TypeScript 4.5.4 (current latest) and currently Nightly version, this code 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?

Also asked on stack overflow

🙂 Expected behavior

We can use all of version 1,2,3,4 without having this TS2322 error.

@RyanCavanaugh RyanCavanaugh added the Working as Intended The behavior described is the intended behavior; this is not a bug label Jan 3, 2022
@PabloLION
Copy link
Author

PabloLION commented Jan 4, 2022

Thank you for explaining me all these, @fatcerberus.
I did see "This conditional type returns never when it should return the true branch" (#31751) in the "not a bug" part, but it seems irrelevant.
And you are right, now I understand it's an intersection. (it can be "string" and can be "number" so it must be intersection of "string" and "number", meanly, "never"). However,,

There are two more doubts I didn't call out:

  1. What is the correct pattern to achieve this purpose, except "as any"? how can I fix it? Please offer some links.
  2. after removing the property "str" or "num", the type of target[prop] changed to number | number[] or string|number[]. Shouldn't (one of)these be "never" as well?

@typescript-bot
Copy link
Collaborator

This issue has been marked 'Working as Intended' and has seen no recent activity. It has been automatically closed for house-keeping purposes.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Working as Intended The behavior described is the intended behavior; this is not a bug
Projects
None yet
Development

No branches or pull requests

5 participants