socketio / socketio/socket.io

TypeScript type breakage under pnpm / preserveSymlinks=true due to extending Emitter from another package

Open
#5,411 2 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

needs investigation
Dominant language
TypeScript
Stars
63.2k
Forks
10.3k
Avg merge
11d 20h
Merged PRs (30d)
2

Description

Is your feature request related to a problem? Please describe.

When using socket.io-client in a symlinked setup (such as pnpm + preserveSymlinks=true or local linking via npm link), TypeScript loses several instance methods (on, emit, etc.) on the Socket class.

This happens because Socket extends the Emitter class from the @socket.io/component-emitter package:

import { Emitter } from "@socket.io/component-emitter";

export class Socket extends Emitter { ... }

Under preserveSymlinks=true, there can be multiple physical copies of @socket.io/component-emitter, resulting in distinct module identities for TypeScript.
As a result, Socket no longer appears to implement the correct emitter API.

This affects:

  • pnpm users (the default node_modules structure is symlink-based)
  • anyone linking socket.io-client locally (e.g. pnpm link, npm link, or monorepo setups)

Describe the solution you'd like

One of the following would make the types robust against symlinked environments:

  • Re-export the emitter types from socket.io-client to unify identity.
  • Use composition instead of inheritance for emitter behavior.
  • Define an internal interface for the emitter API instead of importing the external class.

Example of a minimal re-export solution:

// socket.io-client/index.ts
import { Emitter } from "@socket.io/component-emitter";
export { Emitter }; // re-export canonical symbol

export class Socket extends Emitter { ... }

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 the socket.io-client/index.ts example and the Socket declaration, then trace how @socket.io/component-emitter is imported under preserveSymlinks=true. Reproduce the issue in a pnpm, npm link, or monorepo setup and compare the proposed type-identity approaches. Done means Socket retains its on and emit types when symlinked.

Written by the indexing model from the issue text.

Assessment

Tech stack
typescript
Domain
api, developer-experience
Issue type
Feature
Difficulty
4/5
Estimated time
3-5 days
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
35/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.