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

Restore the ability to type-check stable code #22114

Closed
jsejcksn opened this issue Jan 25, 2024 · 2 comments
Closed

Restore the ability to type-check stable code #22114

jsejcksn opened this issue Jan 25, 2024 · 2 comments
Labels
suggestion suggestions for new features (yet to be agreed) types Issues related to TypeScript types

Comments

@jsejcksn
Copy link
Contributor

Ref:

Here's the message accompanying the linked PR for context here:

This commit removes conditional type-checking of unstable APIs.

Before this commit deno check (or any other type-checking command and the LSP) would error out if there was an unstable API in the code, but not --unstable flag provided.

This situation hinders DX and makes it harder to configure Deno. Failing during runtime unless --unstable flag is provided is enough in this case.

I think the change might have been introduced prematurely, as there is no longer a simple way to type-check stable code.

The change completely mitigates one of the useful safety features of type-checking: preventing use of references that won't exist at runtime for stable code (code that does not use the --unstable runtime argument). By including all of the unstable type declarations during type-checking for all programs unconditionally, an entire class of preventable runtime ReferenceErrors are no longer caught. Although I don't have usage data to support it, I expect that the overwhelming majority of Deno users are not running code using the --unstable flag, especially in production.

Here's a contrived example for demonstration which uses the WebSocketStream class, which is a global that's only available when using the --unstable flag since Deno v1.13.0:

example.ts:

const wss = new WebSocketStream("ws://localhost:8000/live");

const { readable } = await wss.opened;

for await (const _data of readable) {
  // code that handles the socket stream…
}

Type-checking passes (no diagnostics):

% deno check example.ts
Check file:///Users/deno/example.ts

Running the program crashes with an uncaught ReferenceError:

% deno run example.ts
error: Uncaught (in promise) ReferenceError: WebSocketStream is not defined
const wss = new WebSocketStream("ws://localhost:8000/live");
            ^
    at file:///Users/deno/example.ts:1:13

The problem is exaggerated when type-checking is run prior to execution using the --check argument (deno run --check …). The expectation is that a type-checking failure will occur for these kinds of reference errors and prevent execution of the code entirely. From the TypeScript section of the manual (📌):

When using deno run with the --check argument, type-related diagnostics will prevent the program from running: it will halt on these warnings, and exit the process before executing the code.

This was true in previous releases…

% deno --version
deno 1.39.4 (release, aarch64-apple-darwin)
v8 12.0.267.8
typescript 5.3.3

% deno run --check example.ts
Check file:///Users/deno/example.ts
error: TS2304 [ERROR]: Cannot find name 'WebSocketStream'.
const wss = new WebSocketStream("ws://localhost:8000/live");
                ~~~~~~~~~~~~~~~
    at file:///Users/deno/example.ts:1:17

…but after the change, these unavailable reference errors are not caught prior to runtime, and instead they create exceptions:

% deno --version
deno 1.40.1 (release, aarch64-apple-darwin)
v8 12.1.285.6
typescript 5.3.3

% deno run --check example.ts
Check file:///Users/deno/example.ts
error: Uncaught (in promise) ReferenceError: WebSocketStream is not defined
const wss = new WebSocketStream("ws://localhost:8000/live");
            ^
    at file:///Users/deno/example.ts:1:13

The error occurs almost instantly in the simple, contrived example — but in other typically-complex code, a reference error might not be encountered until a deep, nested condition is met somewhere long after execution starts.


Workarounds are available at present, but tedious — they require modifying every program which doesn't use unstable features in order to emulate the previous default compiler behavior. Options include:

  • adding triple-slash directives to every entrypoint module:

    example.ts:

    /// <reference no-default-lib="true" />
    /// <reference lib="deno.window" />
    
    const wss = new WebSocketStream("ws://localhost:8000/live");
    
    const { readable } = await wss.opened;
    
    for await (const _data of readable) {
      // code that handles the socket stream…
    }
  • explicitly configuring compiler options in the program's associated config file:

    deno.json:

    {
      "compilerOptions": {
        "lib": ["deno.window"]
      }
    }

I'm sympathetic to users who want an LSP-enabled experience with less friction while using unstable features… but this change seems like a clear regression, and I hope we can find a better solution.

@kt3k kt3k added the suggestion suggestions for new features (yet to be agreed) label Jan 26, 2024
@Leokuma
Copy link

Leokuma commented Jan 26, 2024

I agree that we have to have a way to statically verify that we're not using unstable feats.

OTOH, I think unstable should be opt-out in Deno 1 and opt-in in Deno 2, as Deno 1 has too many unstable feats, some of which are major APIs - even Deno.serve was unstable until recently. I feel like unstable is almost default in Deno 1.

@lucacasonato lucacasonato added the types Issues related to TypeScript types label Jun 18, 2024
@dsherret
Copy link
Member

dsherret commented Feb 3, 2025

The decision was made to enable this by default because it's just more conveinent for users.

The recommended way to get this functionality now is to do as mentioned in a deno.json:

{
  "compilerOptions": {
    "lib": ["deno.window"]
  }
}

Yes, it's more tedious, but it's also not so bad.

@dsherret dsherret closed this as completed Feb 3, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
suggestion suggestions for new features (yet to be agreed) types Issues related to TypeScript types
Projects
None yet
Development

No branches or pull requests

5 participants