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

Allow types from lib.dom to be imported explicitly via module #46754

Closed
alshdavid opened this issue Nov 9, 2021 · 8 comments
Closed

Allow types from lib.dom to be imported explicitly via module #46754

alshdavid opened this issue Nov 9, 2021 · 8 comments
Labels
Out of Scope This idea sits outside of the TypeScript language design constraints Suggestion An idea for TypeScript

Comments

@alshdavid
Copy link

alshdavid commented Nov 9, 2021

tldr

Allow for the import of libdom types explictly

import { window, console, Window } from 'libdom'

// Or maybe
import { window, console, Window } from '@types/dom'
import { self } from '@types/dom/worker'
import { global, console } from '@types/node'

I am not talking about built-in language features like Array.filter, Proxy, or similar. I'm specifically referring to environment specific functionality like MessageChannel, Fetch, Location, etc

Justification

When consuming builtins like libdom, the entirety of the dom types are included into the global scope (exactly as they are when running JS in the browser).

My issue is, in larger applications or mono repos, having ambient types can cause naming collisions and ambiguous functionality.

Shadowed global variable names

The removal of shadowed global variables will not cause a type error as expected. As an example, if you name a variable name

const name = 'foo'
console.log(name)

Then you later delete name

console.log(name)

Any logic further down that depends on it will still work because it assumes you're referring to window.name.

Unexpected global overwrites

This can also cause issues where certain libraries will override the globals.

For instance if you have a mono repo with a backend and frontend together, the definition for setTimeout is different in @types/node than it is in dom and there is a collision.

If you install styled-components (or have another package using React Native) then they will use the globals for React Native which override fetch and Headers.

Incorrect context specific globals

What if the file I am working in is a Web Worker or Service Worker? These contexts don't have all the functionality of libdom but are offered global types that indicate that they do.

Dependency injection

Lastly, explicit imports are better when it comes to reasoning about dependency injection.

Suggestion

I would love to be able to import global dependencies directly

example:

import { window, console, Window } from 'libdom'

function foo(windowRef: Window) {
  console.log(windowRef.location.href)
}

foo(window)
@andrewbranch andrewbranch added Out of Scope This idea sits outside of the TypeScript language design constraints Suggestion An idea for TypeScript labels Nov 10, 2021
@andrewbranch
Copy link
Member

These imports would be preserved and would consequently fail at runtime. This is not possible.

What if the file I am working in is a Web Worker or Service Worker?

Those files should ideally be contained in a separate tsconfig that sets the appropriate libs.

I would love to be able to import global dependencies directly

Me too, but this is a JS/DOM problem and not something TypeScript can solve.

@alshdavid
Copy link
Author

Those files should ideally be contained in a separate tsconfig that sets the appropriate libs.

I see what you're saying. I'm sure you can understand how unergonomic this is from a development perspective, also we don't have a built-in type library that covers these environments

Me too, but this is a JS/DOM problem and not something TypeScript can solve.

Yeah, you're right. Perhaps this is the role of an external type library and not a responsibility of the TypeScript project itself.

@andrewbranch
Copy link
Member

we don't have a built-in type library that covers these environments

"lib": ["es2018", "webworker"]

should do the trick

@thw0rted
Copy link

thw0rted commented Aug 2, 2022

I asked for a very similar feature over at microsoft/TypeScript-DOM-lib-generator#1207 and it's still open. I'm not sure I actually need it anymore, though...

@andrewbranch
Copy link
Member

The problem with a pretend module that exports only types is that we have no concept of a type-only module. By declaring a module named "web" that exports a bunch of types and no values, you are saying that there exists a real module named "web" that exports nothing. The distinction is important under --importsNotUsedAsValues=preserve, because when the imported types are removed, you’d still end up with import "web" which would fail at runtime. You can get around this by writing import type { ... } from "web", but we have no way of enforcing that. I think type-only modules as a concept are a necessary precondition of a proposal like that—it’s not the first time it’s come up, but it’s not yet clear that the idea is worth its weight.

@danon
Copy link

danon commented Mar 7, 2024

I think type-only modules as a concept are a necessary precondition of a proposal like that—it’s not the first time it’s come up, but it’s not yet clear that the idea is worth its weight.

Isn't it a consequence of the very idea of "lib":["dom"]? Typescript provides types, but only implicitly.

@manzoorwanijk
Copy link

manzoorwanijk commented Mar 25, 2024

Inability to do this actually breaks the code at runtime when using 'jsdom' - DefinitelyTyped/DefinitelyTyped#51276.

Since we can't import the definitions, we need to reference the whole lib, which wrongly sets the globals which never exist in NodeJS and thus breaks the code at runtime.

@danon
Copy link

danon commented Mar 25, 2024

Inability to do this actually breaks the code at runtime when using 'jsdom' - DefinitelyTyped/DefinitelyTyped#51276.

Since we can't import the definitions, we need to reference the whole lib, which wrongly sets the globals which never exist in NodeJS and thus breaks the code on runtime.

Exactly right.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Out of Scope This idea sits outside of the TypeScript language design constraints Suggestion An idea for TypeScript
Projects
None yet
Development

No branches or pull requests

5 participants