Skip to content

[Bug]: tsrx-tsc drops TS1360 when a satisfies check fails #243

Open

Description

@leonidaz

Issue Category

Compilation Bug (command-line type checking).

Bug Description

tsrx-tsc --noEmit exits 0 when a satisfies check fails. TypeScript reports TS1360 (Type 'X' does not satisfy the expected type 'Y') on the satisfies keyword itself, and no mapping covers that keyword. This happens for any operand: a literal, an identifier, a call, this, a parenthesized expression, or a chained as ... satisfies. It also happens in a function body and a component template body.

Reproduction Steps

At 62ef14a7, run pnpm install --frozen-lockfile --ignore-scripts, then create repro/ at the repository root.

repro/package.json:

{"type":"module"}

repro/tsconfig.json:

{
  "tsrx": { "compiler": "@tsrx/preact" },
  "compilerOptions": {
    "module": "ESNext",
    "moduleResolution": "Bundler",
    "target": "ES2022",
    "jsx": "preserve",
    "strict": true,
    "skipLibCheck": true,
    "types": []
  },
  "include": ["case.tsrx"]
}

repro/case.tsrx:

declare const count: number;
declare function load(): number;
export const a = 1 satisfies string;
export const b = count satisfies string;
export const c = load() satisfies string;
export function read() {
	return count as unknown as number satisfies string;
}

Run from the repository root:

node packages/typescript-plugin/src/tsc.js --noEmit --pretty false -p repro/tsconfig.json

Expected (what tsc reports for the same source saved as case.ts):

repro/case.ts(3,20): error TS1360: Type 'number' does not satisfy the expected type 'string'.
repro/case.ts(4,24): error TS1360: Type 'number' does not satisfy the expected type 'string'.
repro/case.ts(5,25): error TS1360: Type 'number' does not satisfy the expected type 'string'.
repro/case.ts(7,36): error TS1360: Type 'number' does not satisfy the expected type 'string'.

Actual: exit 0 with no output.

In a component template body (export function App() @{ const v = 1 satisfies string; <div>{v}</div> }), TS1360 is also dropped. It reports only inside a JSX expression container (<div>{1 satisfies string}</div>), because the container's mapping covers the keyword.

Cause

The TSAsExpression / TSSatisfiesExpression case in packages/tsrx/src/transform/segments.js visits the expression and the type annotation but maps nothing between them. esrap prints the keyword with context.write(' satisfies ') and no location, in 2.3.2 and in 2.3.11. None of the open esrap PRs (sveltejs/esrap#212, #213, #214, #215) change that. With esrap 2.3.11 linked in, the repro still exits 0.

as doesn't have this problem. TypeScript reports TS2352 on the whole "s" as number, and Volar maps its start and end through two different mappings (the operand and the type). TS1360 starts and ends inside the unmapped keyword, so nothing can map it.

Fix Direction

Two options; I haven't tried either:

Environment

  • origin/main at 62ef14a, @tsrx/core 0.3.3, @tsrx/typescript-plugin 0.4.11, @tsrx/preact 0.2.8
  • esrap 2.3.2 (lockfile); also checked with esrap 2.3.11 linked in its place
  • TypeScript 5.9.3
  • Node 24.18.0, pnpm 11.15.1, macOS 26.6.2

Additional Context

Found while fixing #223 (bare this), where this satisfies number was the one shape that still lost its diagnostic. Same family as #216 and #231: the walker has no mapping at the span TypeScript reports on.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions