@reintersect/effect-tsgo
v0.27.3
Published
Effect Language Service for TypeScript-Go — Effect-specific diagnostics and hover features.
Readme
Effect Language Service (TypeScript-Go)
[!IMPORTANT] This is a fork.
@reintersect/effect-tsgois Effect-TS/tsgo plus one extra patch,_patches/028-nativepath-realpath-darwin.patch(microsoft/typescript-go#4578): the macOSF_GETPATHrealpath fast path can nondeterministically return a hardlink sibling's name for files withnlink > 1(microsoft/typescript-go#4262), which breaks module resolution in pnpm- and Nix-style hardlink-deduplicated stores. All packages are renamed to@reintersect/effect-tsgo*; the CLI bin name stayseffect-tsgo.Retirement condition: as soon as upstream typescript-go merges #4578 (or otherwise removes the darwin
F_GETPATHfast path) and that lands in atypescriptrelease consumed by@effect/tsgo, this fork should be abandoned and consumers switched back to@effect/tsgo.Maintenance: the daily
update-typescript-go.ymlcron auto-bumps thetypescript-gosubmodule and revalidates all patches, exactly as upstream does. If that automated PR fails while applying028-nativepath-realpath-darwin.patch, upstream changedinternal/nativepath/realpath_darwin.go— re-port the patch (or, if the change is the fix, retire the fork).CI caveats in this organization: the GitHub enterprise policy forces a read-only default
GITHUB_TOKENand forbids Actions from creating pull requests, and GitHub does not deliver push/pull_request events to this fork's workflows. Consequences:update-typescript-go.ymlandversion.ymlcannot open their PRs withGITHUB_TOKEN(branch pushes with explicit job-levelcontents: writestill work) — either add a fine-grained PAT secret (e.g.GH_PATwithcontents: write+pull-requests: writeon this repo) and switch those workflows to it, or run the changesets/version and upstream-sync steps locally and push. Releases run viaworkflow_dispatchonrelease.ymlwith therelease_shainput (the Version Packages commit onmain); the merge of a Version Packages PR will not trigger it automatically.
Direct usage without patching (fork addition)
CLI: the tsgo bin
The main package ships a second bin, tsgo, which launches the packaged Effect binary for your
platform directly — a plain devDependency gives every consumer a real node_modules/.bin/tsgo
with no typescript install to patch:
pnpm add -D @reintersect/effect-tsgo
pnpm tsgo --project tsconfig.jsonBy default it runs the platform package's lib/tsc (built from generated/latest, tracking npm
typescript@latest). Set ETSGO_CHANNEL=next to run lib/tsc-next (built from main, tracking
typescript@next). Exit codes and stdio pass through unchanged.
Editor: typescript.native-preview.tsdk
The TypeScriptTeam.native-preview VS Code/Cursor extension accepts any directory containing a
binary named tsc or tsgo as a tsdk (it appears in the version picker as "(local)") and starts
it with --lsp, which the packaged binaries support. The platform packages already ship lib/tsc,
so no patching is needed — point the setting at your platform package (the path is
platform-specific):
// .vscode/settings.json
{
"typescript.native-preview.tsdk": "./node_modules/@reintersect/effect-tsgo-darwin-arm64/lib"
}The extension tries tsc before tsc-next in that directory; both are Effect-patched. Requires
@reintersect/effect-tsgo-* >= 0.27.2 — earlier tarballs shipped the binaries without the
executable bit, and the extension spawns them directly. The extension's package-based tsdk
resolution hardcodes the @typescript/<name>-<platform>-<arch> scope, so pointing the setting at
the main package directory does not work; use the lib directory form above (or keep using
effect-tsgo patch against an installed typescript).
A wrapper around TypeScript-Go that builds the Effect Language Service, providing Effect-TS diagnostics and quick fixes. This project targets Effect V4 (codename: "smol") primarily and also Effect V3.
Installation
The setup of the TSGO version of the LSP can be performed via the command line interface:
npx @reintersect/effect-tsgo setupThis will guide you through the installation process, which includes:
- Adding the
@reintersect/effect-tsgodependency to your project. - Configuring your
tsconfig.jsonto use the Effect Language Service plugin. - Adjusting plugin options to your preference.
- Hinting at any additional editor configuration needed to ensure the LSP is active.
[!NOTE] At the moment, you still need a native TypeScript install alongside
@reintersect/effect-tsgo:typescript>= 7 (e.g.typescript@latestortypescript@next) or an alias such as@typescript/native.effect-tsgo patchtriestypescript, then@typescript/native, and accepts--typescript-package <name>to try a custom package name first.
LSP-based linter
The Effect LSP doubles as a tool to perform type-aware linting of Effect code.
Linting can occur either during the tsc typecheck phase (with the benefit of running typechecking only once and caching the output), or via a dedicated npx @reintersect/effect-tsgo diagnostics --project tsconfig.json command (with typechecking occurring again).
When running in tsc mode, the Effect diagnostics are emitted as standard TypeScript diagnostics, and can be configured to affect the tsc exit code through the options ignoreEffectSuggestionsInTscExitCode, ignoreEffectWarningsInTscExitCode, and ignoreEffectErrorsInTscExitCode.
When running in dedicated diagnostics mode, the Effect diagnostics can be emitted in structured formats, which can be further processed by other tools.
Diagnostic Status
Some diagnostics are off by default or have a default severity of suggestion, but you can always enable them or change their default severity in the plugin options.
➖ off by default, ❌ error, ⚠️ warning, 💬 message, 💡 suggestion, 🔧 quick fix available
Refactor Status
| Refactor | V3 | V4 | Notes |
|----------|----|----|-------|
| asyncAwaitToFn | ✅ | ✅ | Convert async/await to Effect.fn |
| asyncAwaitToFnTryPromise | ✅ | ✅ | Convert async/await to Effect.fn with Error ADT + tryPromise |
| asyncAwaitToGen | ✅ | ✅ | Convert async/await to Effect.gen |
| asyncAwaitToGenTryPromise | ✅ | ✅ | Convert async/await to Effect.gen with Error ADT + tryPromise |
| debugPerformance | ❌ | ❌ | Insert performance timing debug comments |
| effectGenToFn | ✅ | ✅ | Convert Effect.gen to Effect.fn |
| functionToArrow | ✅ | ✅ | Convert function declaration to arrow function |
| layerMagic | ✅ | ✅ | Auto-compose layers with correct merge/provide |
| makeSchemaOpaque | ✅ | ✅ | Convert Schema to opaque type aliases |
| makeSchemaOpaqueWithNs | ✅ | ✅ | Convert Schema to opaque types with namespace |
| pipeableToDatafirst | ✅ | ✅ | Convert pipeable calls to data-first style |
| removeUnnecessaryEffectGen | ✅ | ✅ | Remove redundant Effect.gen wrapper |
| structuralTypeToSchema | ✅ | ✅ | Generate recursive Schema from type alias |
| toggleLazyConst | ✅ | ✅ | Toggle lazy/eager const declarations |
| togglePipeStyle | ✅ | ✅ | Toggle pipe(x, f) vs x.pipe(f) |
| toggleReturnTypeAnnotation | ✅ | ✅ | Add/remove return type annotation |
| toggleTypeAnnotation | ✅ | ✅ | Add/remove variable type annotation |
| typeToEffectSchema | ✅ | ✅ | Generate Effect.Schema from type alias |
| typeToEffectSchemaClass | ✅ | ✅ | Generate Schema.Class from type alias |
| wrapWithEffectGen | ✅ | ✅ | Wrap expression in Effect.gen |
| wrapWithPipe | ❌ | ✅ | Wrap selection in pipe(...) |
| writeTagClassAccessors | ✅ | ➖ | Generate static accessors for Effect.Service/Tag classes |
Completion Status
| Completion | V3 | V4 | Notes |
|------------|----|----|-------|
| contextSelfInClasses | ✅ | ➖ | Context.Tag self-type snippets in extends clauses (V3-only) |
| effectDataClasses | ✅ | ✅ | Data class constructor snippets in extends clauses |
| effectSchemaSelfInClasses | ✅ | ✅ | Schema/Model class constructor snippets in extends clauses |
| effectSelfInClasses | ✅ | ➖ | Effect.Service/Effect.Tag self-type snippets in extends clauses (V3-only) |
| genFunctionStar | ✅ | ✅ | gen(function*(){}) snippet when dot-accessing .gen on objects with callable gen property |
| effectCodegensComment | ✅ | ✅ | @effect-codegens directive snippet in comments with codegen name choices |
| effectDiagnosticsComment | ✅ | ✅ | @effect-diagnostics / @effect-diagnostics-next-line directive snippets in comments |
| rpcMakeClasses | ✅ | ➖ | Rpc.make constructor snippet in extends clauses (V3-only) |
| schemaBrand | ✅ | ➖ | brand("varName") snippet when dot-accessing Schema in variable declarations (V3-only) |
| serviceMapSelfInClasses | ✅ | ✅ | Service map self-type snippets in extends clauses |
Best Practices
Relationship to Official TypeScript-Go (tsgo)
Effect-tsgo is a superset of the official TypeScript-Go — it embeds a pinned version of tsgo with a small patch set on top and adds the Effect language service. This means effect-tsgo provides all standard TypeScript-Go functionality plus Effect-specific diagnostics, quick fixes, and refactors.
Use effect-tsgo instead of tsgo, not alongside it. Running both in parallel will produce duplicate diagnostics and degrade editor performance. Configure your editor to use effect-tsgo as your sole TypeScript language server.
Version Pinning
Each release of effect-tsgo is built against a specific upstream tsgo commit. The pinned commit is recorded in flake.nix (typescript-go-src). When upstream tsgo releases new features or fixes, effect-tsgo will adopt them in a subsequent release after validating compatibility with the Effect diagnostics layer.
When to Upgrade
- Upgrade
effect-tsgowhen a new release includes upstreamtsgofixes you need or new Effect diagnostics you want. - There is no need to track upstream
tsgoreleases separately —effect-tsgois the single binary to manage.
Plugin Options
{
"compilerOptions": {
"plugins": [
{
"name": "@effect/language-service",
// Controls Effect refactors. (default: true)
"refactors": true,
// Controls Effect diagnostics. (default: true)
"diagnostics": true,
// When false, suggestion-level Effect diagnostics are omitted from tsc CLI output. (default: true)
"includeSuggestionsInTsc": true,
// Controls Effect quickinfo. (default: true)
"quickinfo": true,
// Controls Effect completions. (default: true)
"completions": true,
// Enables additional debug-only Effect language service output. (default: false)
"debug": false,
// Controls Effect goto references support. (default: true)
"goto": true,
// Controls Effect rename helpers. (default: true)
"renames": true,
// When true, suggestion diagnostics do not affect the tsc exit code. (default: true)
"ignoreEffectSuggestionsInTscExitCode": true,
// When true, warning diagnostics do not affect the tsc exit code. (default: false)
"ignoreEffectWarningsInTscExitCode": false,
// When true, error diagnostics do not affect the tsc exit code. (default: false)
"ignoreEffectErrorsInTscExitCode": false,
// When true, disabled diagnostics are still processed so directives can re-enable them. (default: false)
"skipDisabledOptimization": false,
// Mermaid rendering service for layer graph links. Accepts mermaid.live, mermaid.com, or a custom URL. (default: "mermaid.live")
"mermaidProvider": "mermaid.live",
// When true, suppresses external Mermaid links in hover output. (default: false)
"noExternal": false,
// How many levels deep the layer graph extraction follows symbol references. (default: 0)
"layerGraphFollowDepth": 0,
// When true, suppresses redundant return-type inlay hints on supported Effect generator functions. (default: false)
"inlays": false,
// Package names that should prefer namespace imports. (default: [])
"namespaceImportPackages": [],
// Package names that should prefer barrel named imports. (default: [])
"barrelImportPackages": [],
// Package-level import aliases keyed by package name. (default: {})
"importAliases": {},
// Controls whether named reexports are followed at package top-level. (default: "ignore")
"topLevelNamedReexports": "ignore",
// Configures key pattern formulas for the deterministicKeys rule. (default: [{"target":"service","pattern":"default","skipLeadingPath":["src/"]},{"target":"custom","pattern":"default","skipLeadingPath":["src/"]}])
"keyPatterns": [
{
"target": "service",
"pattern": "default",
"skipLeadingPath": [
"src/"
]
},
{
"target": "custom",
"pattern": "default",
"skipLeadingPath": [
"src/"
]
}
],
// Enables matching constructors with @effect-identifier annotations. (default: false)
"extendedKeyDetection": false,
// Minimum number of contiguous pipeable transformations to trigger missedPipeableOpportunity. (default: 2)
"pipeableMinArgCount": 2,
// Package names allowed to have multiple versions without triggering duplicatePackage. (default: [])
"allowedDuplicatedPackages": [],
// Controls which effectFnOpportunity quickfix variants are offered. (default: ["span"])
"effectFn": [
"span"
],
// Maps rule names to severity levels. Use {} to enable diagnostics with rule defaults. (default: {})
"diagnosticSeverity": {},
// Ordered per-file diagnostic option overrides. (default: [{"include":["src/**/*.ts"],"options":{"diagnosticSeverity":{"floatingEffect":"error"}}}])
"overrides": [
{
"include": [
"src/**/*.ts"
],
"options": {
"diagnosticSeverity": {
"floatingEffect": "error"
}
}
}
]
}
]
}
}