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

problem with reactive handling objects with inner properties that are classes #5920

Open
mprinc opened this issue May 14, 2022 · 4 comments
Open

Comments

@mprinc
Copy link

mprinc commented May 14, 2022

Link to minimal reproduction

https://sfc.vuejs.org/#eyJBcHAudnVlIjoiPHNjcmlwdCAgbGFuZz1cInRzXCIgc2V0dXA+XG5cbiAgaW1wb3J0IHsgcmVhY3RpdmUgfSBmcm9tIFwidnVlXCI7XG5cbiAgY2xhc3MgVGVzdEdlbmVyaWM8ZVggZXh0ZW5kcyBudW1iZXI+IHtcbiAgICBwcm90ZWN0ZWQgeCE6IG51bWJlcjtcbiAgICBjb25zdHJ1Y3Rvcihwcm90ZWN0ZWQgeTogZVgpIHtcbiAgICAgIHRoaXMueCA9IHk7XG4gICAgfVxuICB9XG5cbiAgY2xhc3MgVGVzdENsYXNzIHtcbiAgICBwcm90ZWN0ZWQgeCE6IG51bWJlcjtcbiAgICBjb25zdHJ1Y3Rvcihwcm90ZWN0ZWQgeTogbnVtYmVyKSB7XG4gICAgICB0aGlzLnggPSB5O1xuICAgIH1cbiAgfVxuXG4gIGludGVyZmFjZSBJVGVzdCB7XG4gICAgeDogbnVtYmVyO1xuICAgIHk6IHN0cmluZyB8IHVuZGVmaW5lZDtcbiAgICB0ZXN0R2VuZXJpYzogVGVzdEdlbmVyaWM8bnVtYmVyPiB8IHVuZGVmaW5lZDtcbiAgICB0ZXN0Q2xhc3M6IFRlc3RDbGFzcyB8IHVuZGVmaW5lZDtcbiAgfVxuXG4gIGNvbnN0IHRlc3RPYmo6IElUZXN0ID0ge1xuICAgIHg6IDMsXG4gICAgeTogdW5kZWZpbmVkLFxuICAgIHRlc3RHZW5lcmljOiB1bmRlZmluZWQsXG4gICAgdGVzdENsYXNzOiB1bmRlZmluZWQsXG4gIH07XG5cbiAgLyoqIHRoZXJlIGlzIGVycm9yIG9uIHRoZSBgdGVzdGAgY29uc3RhbnQsIGFzIHJlYWN0aXZlPElUZXN0PiBkb2Vzbid0IHByb3ZpZGUgYElUZXN0YCB0eXBlIHByb3Blcmx5LiBjbGFzc2VzIGBUZXN0R2VuZXJpY2AgYW5kIGBUZXN0Q2xhc3NgIGFyZSBcInRyaW1tZWRcIiB0byBwdXJlIGB7fWAgdHlwZXMgYW5kIHdlIGdhdCBhbiBlcnJvciBsaWtlIFwiYHt9YCBkb2Vzbid0IGNvbnRhaW4gYHhgIGFuZCBgeWBcIi5cbiAgICogSWYgSSByZW1vdmUgYHRlc3RHZW5lcmljYCBhbmQgYHRlc3RDbGFzc2AgbmF0dXJhbGx5LCBlcnJvcnMgYXJlIGdvbmUuXG4gICAqL1xuICBjb25zdCB0ZXN0OiBJVGVzdCA9IHJlYWN0aXZlPElUZXN0Pih0ZXN0T2JqKTtcbiAgY29uc29sZS5sb2coYHRlc3Q6ICR7dGVzdH1gKTtcblxuPC9zY3JpcHQ+XG5cbjx0ZW1wbGF0ZT5cbjwvdGVtcGxhdGU+IiwiaW1wb3J0LW1hcC5qc29uIjoie1xuICBcImltcG9ydHNcIjoge1xuICAgIFwidnVlXCI6IFwiaHR0cHM6Ly91bnBrZy5jb20vQHZ1ZS9ydW50aW1lLWRvbUAzLjIuMzMvZGlzdC9ydW50aW1lLWRvbS5lc20tYnJvd3Nlci5qc1wiXG4gIH1cbn0ifQ==

Steps to reproduce

It is self-contained in the provided the SFC Playground reproduction

What is expected?

It is expected that

const test: ITest = reactive<ITest>(testObj);

works properly in regard to type matching.

What is actually happening?

I get an error from the TypeScript language server in VSC.

TypeScript types matching with reactive are not handling properly classes. It reduces them to empty objects {}

System Info

System:
    OS: macOS 11.4
    CPU: (8) x64 Apple M1
    Memory: 21.72 MB / 16.00 GB
    Shell: 5.8 - /bin/zsh
  Binaries:
    Node: 16.13.0 - /usr/local/bin/node
    Yarn: 1.22.5 - ~/.yarn/bin/yarn
    npm: 8.1.0 - /usr/local/bin/npm
  Browsers:
    Chrome: 101.0.4951.64
    Chrome Canary: 104.0.5061.0
    Edge: 96.0.1054.62
    Firefox: 99.0
    Safari: 14.1.1
  npmPackages:
    vue: ^3.2.33 => 3.2.33

Any additional comments?

If this is a technical limitation and we have to do some workarounds it should be mentioned in reactive doc but there is no mention.

I can imagine we should use interfaces instead of classes but again, it would be a serious drawback for various use-cases.

@mprinc
Copy link
Author

mprinc commented May 14, 2022

I have noticed that the SFC Playground doesn't handle the code properly so here it is again:

<script  lang="ts" setup>

  import { reactive } from "vue";

  class TestGeneric<eX extends number> {
    protected x!: number;
    constructor(protected y: eX) {
      this.x = y;
    }
  }

  class TestClass {
    protected x!: number;
    constructor(protected y: number) {
      this.x = y;
    }
  }

  interface ITest {
    x: number;
    y: string | undefined;
    testGeneric: TestGeneric<number> | undefined;
    testClass: TestClass | undefined;
  }

  const testObj: ITest = {
    x: 3,
    y: undefined,
    testGeneric: undefined,
    testClass: undefined,
  };

  /** there is error on the `test` constant, as reactive<ITest> doesn't provide `ITest` type properly. classes `TestGeneric` and `TestClass` are "trimmed" to pure `{}` types and we gat an error like "`{}` doesn't contain `x` and `y`".
   * If I remove `testGeneric` and `testClass` naturally, errors are gone.
   */
  const test: ITest = reactive<ITest>(testObj);
  console.log(`test: ${test}`);

</script>

<template>
</template>

@John60676
Copy link

What's the status?

@sebastianvitterso
Copy link

sebastianvitterso commented Oct 13, 2023

I ran into the same issue today, the issue has to do with protected properties on classes used inside reactive:

<script setup lang="ts">
import { reactive } from 'vue'

class Person {
  constructor(public name: string){}
  protected species = "HUMAN"
}

const names = [ "Jim", "Pam" ]
const people = reactive(names.map(name => new Person(name)))

function foo(people: Person[]){
  for (const person of people) {
    console.log(person instanceof Person) // all true
  }
}
foo(people)
//  ^ { name: string; }[] !== Person[]

</script>

<template>
  <p v-for="person in people">{{person}} - {{person instanceof Person}}</p>
                    <!-- ^ both objects are instances of Person class ^ -->
</template>

Playground link.

@LinusBorg this was never triaged/picked up by the Vue team, it seems.

@sebastianvitterso
Copy link

sebastianvitterso commented Oct 13, 2023

I can add: I think this is because UnwrapRefSimple<T> depends on the keyof operator, which according to this comment in the TS repo "intentionally does not include non-public members".

So it might not be something that we can get around, unless the type can be made without the usage of the keyof operator, or something like fieldof is added to TypeScript.

Edit: I see now that there are other issues pointing this out.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

4 participants