adaltas / adaltas/node-csv

csv-stringify Browser ESM entry points pollute global types with Node types

Open
#476 3 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Dominant language
JavaScript
Stars
4.3k
Forks
299
Avg merge
16h 19m
Merged PRs (30d)
1

Description

Describe the bug

I'm using csv-stringify in a browser-based Vite + React + Typescript project. The package provides a browser-only entry point: (import { stringify } from "csv-stringify/browser/esm";), but that entry point includes the following TypeScript triple-slash directive in csv-stringify/dist/esm/index.d.ts:

/// <reference types="node" />

This injects NodeJS ambient types into the consumer’s global type environment, even though the entry point is intended for browser usage only. This can lead to typescript type-checking errors caused by unexpected ambient overload resolution.

To Reproduce

Create a Vite + React + Typescript project as follows and install csv-stringify:

npm create vite@8.2.0 csv-stringify-bug -- --template react-ts --no-interactive
cd csv-stringify-bug
npm i csv-stringify

in src/main.tsx, add the following:

import { StrictMode } from 'react'
import { createRoot } from 'react-dom/client'
import './index.css'
import App from './App.tsx'

+ import { stringify } from "csv-stringify/browser/esm";
+
+ const timeout: number = setTimeout(() => {
+     console.log('This is a timeout log message.');
+ }, 1000);
+
+ // prevent unused variable errors
+ console.log(timeout);
+ console.log(stringify);

createRoot(document.getElementById('root')!).render(
  <StrictMode>
    <App />
  </StrictMode>,
)

Run npm run build:

% npm run build      

> csv-stringify-bug@0.0.0 build
> tsc -b && vite build

src/main.tsx:8:7 - error TS2322: Type 'Timeout' is not assignable to type 'number'.

8 const timeout: number = setTimeout(() => {
        ~~~~~~~


Found 1 error.

As indicated above, I get a type checking error because typescript is using the declaration for setTimeout defined in @types/node, which has a return type of NodeJS.Timeout, whereas the browser version has a return type of number. I am aware that it is possible to fix this issue by simply prefixing setTimeout with window, but a browser-only entry point should not require consumers to defensively qualify DOM globals to avoid Node types that should never have been in scope in the first place.

Additional context

The default Vite + React + TypeScript template uses project references and includes a separate tsconfig.node.json which has "types": ["node"] so that vite.config.ts can be written in TypeScript and use Node.js APIs. As a result, many browser-only Vite projects legitimately include Node types for tooling purposes, even though application source files are intended to be DOM-only. For example, I have the following vite.config.ts in another project that uses the node process API:

import { defineConfig, type PluginOption } from "vite";
import react from "@vitejs/plugin-react";

export default defineConfig() => {

    const isHTTPS = process.env.HTTPS_ENABLED === "1";

    return {
        plugins: [
            react()
        ],
        server: {
            open: "/scans/schornpe",
            host: true,
            https: isHTTPS ? {
                key: "/Users/pschorn/Certificates/localhost.key",
                cert: "/Users/pschorn/Certificates/localhost.crt"
            } : undefined
        },
    };
});

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start with csv-stringify/dist/esm/index.d.ts and inspect how the browser/esm entry point reaches that declaration. Reproduce the issue in a Vite React TypeScript app with npm run build, then verify that importing the browser entry point no longer introduces NodeJS global types and that the example compiles with the browser setTimeout type.

Written by the indexing model from the issue text.

Assessment

Tech stack
node.js, react, typescript, vite
Domain
frontend
Issue type
Bug
Difficulty
2/5
Estimated time
1-3 hours
Activity status
Stale
Clarity
Clearly specified
Newbie friendliness
50/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.