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

Typings error for an reactive object when a property is an Interface that has a private member #2557

Closed
bangjelkoski opened this issue Nov 4, 2020 · 6 comments

Comments

@bangjelkoski
Copy link

Version

3.0.2

Reproduction link

https://codesandbox.io/s/focused-ives-64y66?file=/src/useWallet.ts

Steps to reproduce

If you check the Codesandbox example, file useWallet hover on the line 33 you will see the issue that happens.

This doesn't happen on a barebone typescript project (as shown here Typescript Example)

What is expected?

The person property to have the Person type.

What is actually happening?

The person property has an "objectfied" Person type.


This happens only when there are private properties to the interface.

@LinusBorg
Copy link
Member

LinusBorg commented Nov 5, 2020

The problem is located here:

https://github.com/vuejs/vue-next/blob/a15ec11d03e6a41a975bf2daa72c87f01bd5bd32/packages/reactivity/src/ref.ts#L251

The index signature makes TS loose the Person type and only contains public properties.

Plain TS example:

TS Playground Repro

This will be one for the TS experts (so not me)


workaround

reactive(state) as State

@LinusBorg LinusBorg added 🐞 bug Something isn't working scope: types labels Nov 5, 2020
@LinusBorg
Copy link
Member

LinusBorg commented Nov 5, 2020

Update:

This solves the immediate error but dts tests currently fail on unrelated code for me locally so I can't completely verify:

This breaks unwrapping.

type UnwrappedObject<T> = T & { [P in keyof T]: UnwrapRef<T[P]> } & SymbolExtract<T> 

@LinusBorg LinusBorg removed the 🐞 bug Something isn't working label Nov 5, 2020
@LinusBorg
Copy link
Member

So this will probably have to stay a caveat that requires typecasting. We have to loose the T type in order to have the Unwrapping of possibly nested Refs working.

In this specific scenario it means that the private field is "lost" and the class's type has to be cast manually.

@pikax
Copy link
Member

pikax commented Nov 5, 2020

when you convert an object to reactive vue will unwrap all possible ref properties, to do that we create a new type which should be identical to the original one (if no property was unwrapped). Usually typescript is able to automatically infer the correct type after unwrapping, but because you have private name, which is technically a property that you don't have access outside of your class, vue will not infer it.

But if you check the intellisense you will see the types provide the same method but typescript cannot infer the correct type, this again is caused by the private name, for typescript to archive the private field it basically hide it in a symbol property:

class Person {
  private name: string
}
// should have the equivalent type
const person = ()=> {
 [Symbol('name')]: string
}

As for the new type creation vue needs to unwrap because of this:

class PersonOther  {
 name: Ref<number>
}

const a = reactive(new PersonOther)

a.name // is a string

@hyf0
Copy link
Contributor

hyf0 commented May 25, 2021

Will be fixed in #3791. Duplicate of #2981. May close this one? @HcySunYang

@HcySunYang
Copy link
Member

Duplicate of #2981

@HcySunYang HcySunYang marked this as a duplicate of #2981 May 25, 2021
@github-actions github-actions bot locked and limited conversation to collaborators Oct 20, 2023
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

No branches or pull requests

5 participants