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

Typescript: Private fields in classes on data properties cause failed type verification since 3.0.8 #3815

Closed
tonyfinn opened this issue May 22, 2021 · 4 comments

Comments

@tonyfinn
Copy link

Version

3.0.11

Reproduction link

https://github.com/tonyfinn/vue-ts-error

Steps to reproduce

There are two projects in the reproduction example.

ts-type-error uses Vue 3.0.8 (but 3.0.11 is also broken). works uses Vue 3.0.7. The two projects are otherwise identical.

Both are using Vue CLI, so can be built by running npm run serve

What is expected?

Both projects would build or fail with the same result.

What is actually happening?

works builds correctly and runs correctly.

ts-type-error fails to build with the following error:

ERROR in src/App.vue:36:15
TS2345: Argument of type '{ readonly bar: string; log: () => void; }' is not assignable to parameter of type 'Foo'.
  Property 'baz' is missing in type '{ readonly bar: string; log: () => void; }' but required in type 'Foo'.
    34 |   methods: {
    35 |     clickHandler() {
  > 36 |       usesFoo(this.foo);
       |               ^^^^^^^^
    37 |     }
    38 |   }
    39 | })

The issue appears to be with the private fields. Inside the component methods, this.foo is not of type Foo as of 3.0.8, only of a type that is effectively the public fields/interface of Foo only. This means that when you use Foo as a type in a function declaration, passing this.foo is rejected, as it is missing the private fields as far as the type checker can see.

This appears to be a type checker issue only, if you change clickHandler to:


    clickHandler() {
      usesFoo((this.foo as any) as Foo);
    }

Then you can observe that the log messages are printed upon clicking the text at runtime.

@tonyfinn tonyfinn changed the title Private fields in classes on data properties are broken since 3.0.8 Typescript: Private fields in classes on data properties are broken since 3.0.8 May 22, 2021
@tonyfinn tonyfinn changed the title Typescript: Private fields in classes on data properties are broken since 3.0.8 Typescript: Private fields in classes on data properties fail type verification since 3.0.8 May 22, 2021
@tonyfinn tonyfinn changed the title Typescript: Private fields in classes on data properties fail type verification since 3.0.8 Typescript: Private fields in classes on data properties cause failed type verification since 3.0.8 May 22, 2021
@hyf0
Copy link
Contributor

hyf0 commented May 22, 2021

This is caused by the feature auto unwrap refs on public instance data .

type of data will be put in UnwrapNestedRefs<Data>, which will deeply unwrap the data object. So your type 'Foo' will be put in { [K in keyof T]: UnwrapRefSimple<T[K]> } as T.

After putting, type Foo will become { readonly bar: string; log: () => void; } and lose the private filed baz.

TypeScript is a structural type system. When we compare two different types, regardless of where they came from, if the types of all members are compatible, then we say the types themselves are compatible.
However, when comparing types that have private and protected members, we treat these types differently. For two types to be considered compatible, if one of them has a private member, then the other must have a private member that originated in the same declaration. The same applies to protected members. link

The sturcture of type Foo is equal to { readonly bar: string; log: () => void; } , if you ignore the private fields. typescript won't ,so it break.

It seems that the break could not be fixed easily because of the feature auto unwrapping and limitation of typescript. Easiest way to solve this problem is usesFoo((this.foo as any) as Foo).

@hyf0
Copy link
Contributor

hyf0 commented May 23, 2021

@tonyfinn You can also use this.$data.foo, whose type is Foo. Nevertheless, that will disable auto unwrapping in type and cause inconsistency between static type and runtime type.

@hyf0
Copy link
Contributor

hyf0 commented May 23, 2021

you could close this issue. duplicate with #2981. see fix #3791.

@HcySunYang
Copy link
Member

Duplicate of #2981

@HcySunYang HcySunYang marked this as a duplicate of #2981 May 23, 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.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants