Skip to content

Conversation

@fubhy
Copy link
Contributor

@fubhy fubhy commented Jan 13, 2026

Disclaimer

This summary and diff breakdown was generated by AI (obviously). This message here is written by me :-)

I've been experimenting with tsgo in our current work-in-progress effect v4 codebase (https://github.com/Effect-TS/effect-smol). The great news is, we can already build the entire repository with tsgo after the most recent fixes to project reference handling.

I thought I'd share the following breakdown of declaration file output differences observed in comparison between tsc and tsgo on our codebase.

If this is not useful, please feel free to close this. Otherwise I'd be happy to try & help work on some of the items categorised in the summary below.

Each diff category comes with a minimal test case.

Summary Table

Category Impact tsc (expected) tsgo (current)
Type alias preservation High NonEmptyArray<A> [A, ...A[]]
Array type syntax High Array<A> A[]
ReadonlyArray syntax High ReadonlyArray<A> readonly A[]
Rest param with tuple type High ...elements: NonEmptyArray<A> elements_0: A, ...elements: A[]
Indexed access types High Config["Options"] { readonly timeout: number; ... }
Nested indexed access High Nested["Level1"]["Level2"] { readonly value: string; }
Default type params Medium Effect<A> Effect<A, never, never>
Many default params Medium Channel<string> Channel<string, never, void, unknown, unknown, unknown, never>
Namespace type alias Medium Pull.ExcludeHalt<E> Exclude<E, Pull.Halt<unknown>>
Namespace tuple type Medium Arr.NonEmptyReadonlyArray<A> readonly [A, ...A[]]
Iterator type params Low Iterator<A, L> Iterator<A, L, any>
AsyncIterator params Low AsyncIterator<A, L> AsyncIterator<A, L, any>
Optional return type Low (): Options | undefined (): Options
Union member ordering Low "sliding" | "dropping" | "suspend" "dropping" | "sliding" | "suspend"

Test Files

Each divergence has a corresponding test in testdata/tests/cases/compiler/:

  • declarationEmitTypeAliasPreservation.ts - Type alias and array syntax
  • declarationEmitIndexedAccessPreservation.ts - Indexed access types
  • declarationEmitDefaultTypeParams.ts - Default type parameter elision
  • declarationEmitNamespaceTypePreservation.ts - Namespace-qualified types
  • declarationEmitOptionalParams.ts - Optional parameter representation
  • declarationEmitIteratorTypeParams.ts - Iterator/Generator type params
  • declarationEmitOptionalObjects.ts - Optional objects and return types

Notes

Tests contain tsc's expected output as baselines; they should pass once tsgo matches in behavior

Copilot AI review requested due to automatic review settings January 13, 2026 13:48
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR adds comprehensive test cases documenting the current differences in declaration file (.d.ts) output between TypeScript's tsc and the tsgo port. The tests serve as both documentation of current divergences and as targets for future convergence work.

Changes:

  • Added 7 new compiler test files covering different declaration emit scenarios
  • Added corresponding baseline reference files showing expected tsc output
  • Tests cover type alias preservation, indexed access types, default type parameters, namespace-qualified types, optional parameters, and iterator type parameters

Reviewed changes

Copilot reviewed 14 out of 14 changed files in this pull request and generated 7 comments.

Show a summary per file
File Description
testdata/tests/cases/compiler/declarationEmitTypeAliasPreservation.ts Tests preservation of type aliases like NonEmptyArray and Array/ReadonlyArray syntax in declarations
testdata/tests/cases/compiler/declarationEmitOptionalParams.ts Tests optional parameter representation in declaration emit
testdata/tests/cases/compiler/declarationEmitOptionalObjects.ts Tests optional object parameters and return types in declarations
testdata/tests/cases/compiler/declarationEmitNamespaceTypePreservation.ts Tests preservation of namespace-qualified types in declaration output
testdata/tests/cases/compiler/declarationEmitIteratorTypeParams.ts Tests Iterator/AsyncIterator type parameter handling in declarations
testdata/tests/cases/compiler/declarationEmitIndexedAccessPreservation.ts Tests preservation of indexed access types in declaration emit
testdata/tests/cases/compiler/declarationEmitDefaultTypeParams.ts Tests elision of default type parameters in declaration output
testdata/baselines/reference/compiler/declarationEmitTypeAliasPreservation.js Baseline showing expected tsc output for type alias preservation
testdata/baselines/reference/compiler/declarationEmitOptionalParams.js Baseline showing expected tsc output for optional parameters
testdata/baselines/reference/compiler/declarationEmitOptionalObjects.js Baseline showing expected tsc output for optional objects
testdata/baselines/reference/compiler/declarationEmitNamespaceTypePreservation.js Baseline showing expected tsc output for namespace types
testdata/baselines/reference/compiler/declarationEmitIteratorTypeParams.js Baseline showing expected tsc output for iterator types
testdata/baselines/reference/compiler/declarationEmitIndexedAccessPreservation.js Baseline showing expected tsc output for indexed access types
testdata/baselines/reference/compiler/declarationEmitDefaultTypeParams.js Baseline showing expected tsc output for default type parameters

@jakebailey
Copy link
Member

You should test with #2459, this is still a WIP area

@jakebailey
Copy link
Member

I am a little confused as to how these are high-priority issues; are these not all identical semantically?

@fubhy
Copy link
Contributor Author

fubhy commented Jan 22, 2026

I am a little confused as to how these are high-priority issues; are these not all identical semantically?

They are not. Ignore the rating, that's LLM slop. Most of them are indeed semantically identical. Except for this one:

// Before:
(): Options | undefined

// After:
(): Options

The other's are mostly QoL / readability related (and I'd personally lean towards "before" as being more readable).

@jakebailey
Copy link
Member

I'm a little confused. When I make a test out of:

export const getConfig = (): Options | undefined => undefined

The output is:

export declare const getConfig: () => Options | undefined;

@jakebailey
Copy link
Member

I'd personally lean towards "before" as being more readable

Yes, and this is what #2459 will effectively do, by preserving types as-written.

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants