live_toast icon indicating copy to clipboard operation
live_toast copied to clipboard

TS compilation issue

Open AJReade opened this issue 6 months ago • 0 comments

TypeScript Compiler Crash with moduleResolution: "bundler"

Summary

The live_toast dependency causes a TypeScript compiler crash when imported in projects using moduleResolution: "bundler". The crash occurs with an internal TypeScript error: "Debug Failure. False expression" in the getConstructorDefinedThisAssignmentTypes function.

Environment

  • TypeScript Version: 5.4.5 (also tested with 5.8.3)
  • Node.js Version: v22.12.0
  • Operating System: macOS 24.5.0
  • live_toast Version: [version from deps/live_toast]

TypeScript Configuration

{
  "compilerOptions": {
    "target": "ES2020",
    "lib": ["dom", "dom.iterable", "ES2020"],
    "allowJs": true,
    "skipLibCheck": true,
    "types": ["vite/client"],
    "esModuleInterop": true,
    "allowSyntheticDefaultImports": true,
    "strict": true,
    "forceConsistentCasingInFileNames": true,
    "module": "esnext",
    "moduleResolution": "bundler",
    "isolatedModules": true,
    "resolveJsonModule": true,
    "noEmit": true,
    "jsx": "react"
  }
}

Reproduction Steps

  1. Create a TypeScript project with moduleResolution: "bundler"
  2. Import createLiveToastHook from live_toast:
    import { createLiveToastHook } from "../../deps/live_toast";
    
  3. Run TypeScript compilation: npx tsc

Expected Behavior

TypeScript compilation should complete successfully.

Actual Behavior

TypeScript compiler crashes with the following error:

Error: Debug Failure. False expression.
    at getConstructorDefinedThisAssignmentTypes (/path/to/node_modules/typescript/lib/tsc.js:52803:11)
    at getWidenedTypeForAssignmentDeclaration (/path/to/node_modules/typescript/lib/tsc.js:52614:78)
    at getTypeOfVariableOrParameterOrPropertyWorker (/path/to/node_modules/typescript/lib/tsc.js:53029:14)
    at getTypeOfVariableOrParameterOrProperty (/path/to/node_modules/typescript/lib/tsc.js:52974:20)
    at getTypeOfSymbol (/path/to/node_modules/typescript/lib/tsc.js:53306:14)
    at getWriteTypeOfSymbol (/path/to/node_modules/typescript/lib/tsc.js:53284:29)
    at checkPropertyAccessExpressionOrQualifiedName (/path/to/node_modules/typescript/lib/tsc.js:70818:116)
    at checkPropertyAccessExpression (/path/to/node_modules/typescript/lib/tsc.js:70576:94)
    at checkExpressionWorker (/path/to/node_modules/typescript/lib/tsc.js:76295:16)
    at checkExpression (/path/to/node_modules/typescript/lib/tsc.js:76216:32)

Root Cause Analysis

The issue appears to be caused by the global interface extension in live_toast.ts:

declare global {
  interface HTMLElement {
    order: number
    targetDestination: string
  }
}

When TypeScript uses moduleResolution: "bundler", it encounters a bug in its type inference system when processing property access chains on these extended global interfaces, particularly in the context of constructor-defined property assignments.

Workarounds Attempted

  1. Skipping TypeScript compilation - Works but loses type checking benefits
  2. Using @ts-ignore - Doesn't prevent the crash
  3. Excluding files with exclude - Still processes imports
  4. Creating wrapper files - Still triggers the crash
  5. Custom type declarations - Doesn't resolve the internal compiler bug

Working Workaround

Currently, the only viable workaround is to skip TypeScript type checking in the build process:

{
  "scripts": {
    "build": "vite build"  // instead of "tsc && vite build"
  }
}

Suggested Fixes

  1. Modify the global interface extension to use optional properties:

    declare global {
      interface HTMLElement {
        order?: number;
        targetDestination?: string;
      }
    }
    
  2. Use a more specific interface instead of extending the global HTMLElement:

    interface LiveToastElement extends HTMLElement {
      order: number;
      targetDestination: string;
    }
    
  3. Add a TypeScript configuration note in the documentation about moduleResolution compatibility

Additional Context

  • The crash occurs specifically with moduleResolution: "bundler"
  • Works fine with moduleResolution: "node"
  • The issue is reproducible across different TypeScript versions (5.4.5 and 5.8.3)
  • This affects Phoenix LiveView projects using modern TypeScript configurations

Impact

This issue prevents developers from using modern TypeScript configurations (moduleResolution: "bundler") with live_toast, forcing them to either:

  • Use older module resolution strategies
  • Skip type checking entirely
  • Avoid using live_toast

Would appreciate any guidance on resolving this TypeScript compatibility issue!

AJReade avatar Jun 26 '25 00:06 AJReade