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

Type Unwrapping Bails on all types without DOM lib (e.g. Node.js target) #10485

Open
delaneyb opened this issue Mar 9, 2024 · 1 comment
Open

Comments

@delaneyb
Copy link

delaneyb commented Mar 9, 2024

Vue version

3.4.21

Link to minimal reproduction

https://play.vuejs.org/#eNp9UcFuwjAM/RUrlzKpKgduCCZtE5N22SaGtMOyQ2hdCAtxlKTAhvrvc1oB24VDlMTv2X7PPoo754pdg2IsJqH02kUIGBsHRtnVVIoYpLiVVm8d+QhH8KjKqHeY86uGFmpPW8i4QCattCXZEKFSUcH0TB0cpQWoicYpZ5Atlc9upG35SBu/HcIj0SLdU0hfqrsKBWcADIewWOsAYU2NqWCtdghLRAuN3XvlHFYQCRSE6LVd5WCJDURtDLM4PMd60kNsolfXV3on/8X9To0Kj86oEnt1OWQb9ZNETob9UDhb5DwMLlHrVbEJZHlinTEpSto6bdC/uKi5hRRj6JCEpeZlTKHoG8xP4U04pJgUrx4D+h1Kccai8ivsUqSYvT3jgd9ncEtVY5h9BZxjINMkKT3tvrEVq/vDU8bQ/qlbKU9mEWaHiDactP8TavQyxT4u3T4T1HYEKXjxD1fcX6yMilGXx3sX7S/YwdJg

Steps to reproduce

Specify lib: ['ESNext'] in tsconfig.json

Attempt to use a ref() inside a reactive() where it should be unwrapped so that accessing it does not require .value. E.g.

import { reactive, ref } from 'vue'

const data = reactive({
  foo: ref('bar')
})

type FooType = typeof data.foo  // This should have been unwrapped to a string, not still be a Ref<string>
const shouldWork = data.foo.replace('bar', 'jaz')

What is expected?

.value should not be required

What is actually happening?

Vue's type system bails unwrapping the type immediately, due to the following from @vue/runtime-dom/dist/runtime-dom.d.ts:

declare module '@vue/reactivity' {
    interface RefUnwrapBailTypes {
        runtimeDOMBailTypes: Node | Window;
    }
}

We are not using the DOM lib in tsconfig since this is a Node.js target, and as a result Node | Window evaluates to any, causing Vue's type system to now bail on unwrapping anything.

System Info

System:
    OS: macOS 14.1.2
    CPU: (11) arm64 Apple M3 Pro
    Memory: 114.34 MB / 36.00 GB
    Shell: 5.9 - /bin/zsh
  Binaries:
    Node: 18.19.1 - /usr/local/bin/node
    Yarn: 3.2.4 - /opt/homebrew/bin/yarn
    npm: 10.2.4 - /usr/local/bin/npm
    pnpm: 8.6.8 - /opt/homebrew/bin/pnpm
  Browsers:
    Chrome: 122.0.6261.112
    Safari: 17.1.2

Any additional comments?

A workaround for this is to explicitly install only @vue/runtime-core, since in theory we are working on a Node application, why would we need runtime-dom etc, anyway?

However this is unideal in monorepo setups where vue is installed either alone, or as well, at the root. There should be no need to specifically install the runtime-core package, as bundlers will shake out what's unnecessary from 'vue' when used for non-browser targets.

I have found a simple ambient module type Node = never declaration resolves the issue, but I'm unsure whether this could have side effects for browser-targeted applications.

Perhaps a safer solution could be:
In runtime-dom/dist/runtime-dom.d.ts:

/** Conditionally return one of two types based on whether the passed type is `any` */
type IfAny<T, Y, N> = 0 extends (1 & T) ? Y : N
declare module '@vue/reactivity' {
    interface RefUnwrapBailTypes {
        runtimeDOMBailTypes: IfAny<Node, never, Node> | Window;
    }
}
@itsmnthn
Copy link

itsmnthn commented Mar 23, 2024

I feel this is related vuejs/language-tools#4469 getting vscode type errors from typescript@5.4

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

3 participants