-
-
Notifications
You must be signed in to change notification settings - Fork 8.3k
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
[@vue/reactivity][typing] Unwrapping breaks classes with private fields. #2981
Comments
Ref<T>
is not aligned with the return type of ref
function
This is a pretty bad caveat stemming from a combination of things: This is a limitation in Typescript, when using private properties in classes the Unwrapping that reactivity is doing:
The code does work at runtime though, as the private field is technically still "there", but for TS to be happy, you need to help TS out: A. Unwrap it: interface FooService {
readonly foo: Ref<UnwrapRef<Foo>>;
} B. Typecast it: class FooServiceImpl implements FooService {
foo = ref(new Foo()) as Ref<Foo>;
} In both instances though, you would need to cast it back to its original value when passing it to something that expects an instance of fooUi({ foo: fooService.foo.value as Foo }); None of this is ideal, but short of dropping the Unwrapping behavior, which would be a gigantic breaking change, there's little we can do. A general recommendation would be to:
Sidenote: Native private fieldsthe situation is even worse when using native private fields, which will be coming to JS: class Foo {
public bar = 1;
#baz = "a";
} Those are completely incompatible with Proxies at runtime as well. So instances of such classes need to be marked as raw so that Vue never replaces them with a reactive proxy: const fooRef = ref(marRaw(new Foo())) All of this definitely needs propery documentation in vuejs/docs-next. |
Ref<T>
is not aligned with the return type of ref
function
Just want to note that an issue from the ethers.js repository is related to this / depends on this issue: |
I'm inclined to close this issue as there's nothing to fix for us. TS behaves the way it does and we can't work around that. Javascript private fields also seem to be designed not to work with proxies, so there's nothing we can do, really. |
I'll close this issue because when you assign a value to a As a workaround you can define it as a Bail type, that will prevent from specific classes from unwrapping the type, bear in mind the runtime behaviour will be kept the same, use this carefully. declare module '@vue/reactivity' {
export interface RefUnwrapBailTypes {
classes: Foo
}
} Other way to solve this issue is marking let foo: Foo = ref(markRaw(new Foo())).value
// @ts-expect-error .value is not Foo
let fooError: Foo = ref(new Foo()).value |
Version
3.0.5
Reproduction link
https://codesandbox.io/s/refvalue-strips-off-all-private-fields-2ws44?file=/src/index.ts
Steps to reproduce
What is expected?
Type system is happy with either of the cases.
What is actually happening?
Type system is complaining
A naive suggestion is to change the definition of
Ref
generic type to truly reflect the return type ofref
function, as the problem is caused by the mis-alignment between the actual return type ofref
function and theRef
type definition.ref
function's return type involves Mapped types whileRef<T>
simply has a membervalue
of typeT
.The text was updated successfully, but these errors were encountered: