Skip to content

Effect-TS/tsgo

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

151 Commits
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Effect Language Service (TypeScript-Go)

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.

Currently in Alpha

The TypeScript-Go version of the Effect LSP should be considered in Alpha. Expect breaking changes between releases and some missing features compared to previous version. Some of them are currently on hold due to not yet complete pipeline on the upstream TypeScript repository.

Installation

The setup of the TSGO version of the LSP can be performed via the command line interface:

npx @effect/tsgo setup

This will guide you through the installation process, which includes:

  1. Adding the @effect/tsgo dependency to your project.
  2. Configuring your tsconfig.json to use the Effect Language Service plugin.
  3. Adjusting plugin options to your preference.
  4. Hinting at any additional editor configuration needed to ensure the LSP is active.

Note

At the moment, you still need the standard native TypeScript install (@typescript/native-preview) alongside @effect/tsgo.

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.

DiagnosticSevFixDescriptionv3v4
Correctness Wrong, unsafe, or structurally invalid code patterns.
anyUnknownInErrorContextβž–Detects 'any' or 'unknown' types in Effect error or requirements channelsβœ“βœ“
classSelfMismatchβŒπŸ”§Ensures Self type parameter matches the class name in Context/Service/Tag/Schema classesβœ“βœ“
duplicatePackage⚠️Warns when multiple versions of an Effect-related package are detected in the programβœ“βœ“
effectFnImplicitAny❌Mirrors noImplicitAny for unannotated Effect.fn, Effect.fnUntraced, and Effect.fnUntracedEager callback parameters when no outer contextual function type exists. Requires TS's noImplicitAny: trueβœ“βœ“
floatingEffect❌Detects Effect values that are neither yielded nor assignedβœ“βœ“
genericEffectServices⚠️Prevents services with type parameters that cannot be discriminated at runtimeβœ“βœ“
missingEffectContext❌Detects Effect values with unhandled context requirementsβœ“βœ“
missingEffectErrorβŒπŸ”§Detects Effect values with unhandled error typesβœ“βœ“
missingLayerContext❌Detects Layer values with unhandled context requirementsβœ“βœ“
missingReturnYieldStarβŒπŸ”§Suggests using return yield* for Effects that never succeedβœ“βœ“
missingStarInYieldEffectGenβŒπŸ”§Detects bare yield (without *) inside Effect generator scopesβœ“βœ“
nonObjectEffectServiceType❌Ensures Effect.Service types are objects, not primitivesβœ“
outdatedApi⚠️Detects usage of APIs that have been removed or renamed in Effect v4βœ“
overriddenSchemaConstructorβŒπŸ”§Prevents overriding constructors in Schema classes which breaks decoding behaviorβœ“βœ“
Anti-pattern Discouraged patterns that often lead to bugs or confusing behavior.
catchUnfailableEffectπŸ’‘Warns when using error handling on Effects that never failβœ“βœ“
effectFnIifeβš οΈπŸ”§Effect.fn or Effect.fnUntraced is called as an IIFE; use Effect.gen insteadβœ“βœ“
effectGenUsesAdapter⚠️Warns when using the deprecated adapter parameter in Effect.genβœ“βœ“
effectInFailure⚠️Warns when an Effect is used inside an Effect failure channelβœ“βœ“
effectInVoidSuccess⚠️Detects nested Effects in void success channels that may cause unexecuted effectsβœ“βœ“
globalErrorInEffectCatch⚠️Warns when catch callbacks return global Error type instead of typed errorsβœ“βœ“
globalErrorInEffectFailure⚠️Warns when the global Error type is used in an Effect failure channelβœ“βœ“
layerMergeAllWithDependenciesβš οΈπŸ”§Detects interdependencies in Layer.mergeAll calls where one layer provides a service that another layer requiresβœ“βœ“
lazyPromiseInEffectSync⚠️Warns when Effect.sync lazily returns a Promise instead of using an async Effect constructorβœ“βœ“
leakingRequirementsπŸ’‘Detects implementation services leaked in service methodsβœ“βœ“
multipleEffectProvideβš οΈπŸ”§Warns against chaining Effect.provide calls which can cause service lifecycle issuesβœ“βœ“
returnEffectInGenπŸ’‘πŸ”§Warns when returning an Effect in a generator causes nested Effect<Effect<...>>βœ“βœ“
runEffectInsideEffectπŸ’‘πŸ”§Suggests using Runtime or Effect.run*With methods instead of Effect.run* inside Effect contextsβœ“βœ“
schemaSyncInEffectπŸ’‘Suggests using Effect-based Schema methods instead of sync methods inside Effect generatorsβœ“
scopeInLayerEffectβš οΈπŸ”§Suggests using Layer.scoped instead of Layer.effect when Scope is in requirementsβœ“
strictEffectProvideβž–Warns when using Effect.provide with layers outside of application entry pointsβœ“βœ“
tryCatchInEffectGenπŸ’‘Discourages try/catch in Effect generators in favor of Effect error handlingβœ“βœ“
unknownInEffectCatch⚠️Warns when catch callbacks return unknown instead of typed errorsβœ“βœ“
Effect-native Prefer Effect-native APIs and abstractions when available.
asyncFunctionβž–Warns when declaring async functions and suggests using Effect values and Effect.gen for async control flowβœ“βœ“
cryptoRandomUUIDβž–Warns when using crypto.randomUUID() outside Effect generators instead of the Effect Random module, which uses Effect-injected randomness rather than the crypto module behind the scenesβœ“
cryptoRandomUUIDInEffectβž–Warns when using crypto.randomUUID() inside Effect generators instead of the Effect Random module, which uses Effect-injected randomness rather than the crypto module behind the scenesβœ“
extendsNativeErrorβž–Warns when a class directly extends the native Error classβœ“βœ“
globalConsoleβž–Warns when using console methods outside Effect generators instead of Effect.log/Loggerβœ“βœ“
globalConsoleInEffectβž–Warns when using console methods inside Effect generators instead of Effect.log/Loggerβœ“βœ“
globalDateβž–Warns when using Date.now() or new Date() outside Effect generators instead of Clock/DateTimeβœ“βœ“
globalDateInEffectβž–Warns when using Date.now() or new Date() inside Effect generators instead of Clock/DateTimeβœ“βœ“
globalFetchβž–Warns when using the global fetch function outside Effect generators instead of the Effect HTTP clientβœ“βœ“
globalFetchInEffectβž–Warns when using the global fetch function inside Effect generators instead of the Effect HTTP clientβœ“βœ“
globalRandomβž–Warns when using Math.random() outside Effect generators instead of the Random serviceβœ“βœ“
globalRandomInEffectβž–Warns when using Math.random() inside Effect generators instead of the Random serviceβœ“βœ“
globalTimersβž–Warns when using setTimeout/setInterval outside Effect generators instead of Effect.sleep/Scheduleβœ“βœ“
globalTimersInEffectβž–Warns when using setTimeout/setInterval inside Effect generators instead of Effect.sleep/Scheduleβœ“βœ“
instanceOfSchemaβž–πŸ”§Suggests using Schema.is instead of instanceof for Effect Schema typesβœ“βœ“
newPromiseβž–Warns when constructing promises with new Promise instead of using Effect APIsβœ“βœ“
nodeBuiltinImportβž–Warns when importing Node.js built-in modules that have Effect-native counterpartsβœ“βœ“
preferSchemaOverJsonπŸ’‘Suggests using Effect Schema for JSON operations instead of JSON.parse/JSON.stringifyβœ“βœ“
processEnvβž–Warns when reading process.env outside Effect generators instead of using Effect Configβœ“βœ“
processEnvInEffectβž–Warns when reading process.env inside Effect generators instead of using Effect Configβœ“βœ“
Style Cleanup, consistency, and idiomatic Effect code.
catchAllToMapErrorπŸ’‘πŸ”§Suggests using Effect.mapError instead of Effect.catch + Effect.failβœ“βœ“
deterministicKeysβž–πŸ”§Enforces deterministic naming for service/tag/error identifiers based on class namesβœ“βœ“
effectDoNotationβž–Suggests using Effect.gen or Effect.fn instead of the Effect.Do notation helpersβœ“βœ“
effectFnOpportunityπŸ’‘πŸ”§Suggests using Effect.fn for functions that return an Effectβœ“βœ“
effectMapFlattenπŸ’‘Suggests using Effect.flatMap instead of Effect.map followed by Effect.flatten in piping flowsβœ“βœ“
effectMapVoidπŸ’‘πŸ”§Suggests using Effect.asVoid instead of Effect.map(() => void 0), Effect.map(() => undefined), or Effect.map(() => {})βœ“βœ“
effectSucceedWithVoidπŸ’‘πŸ”§Suggests using Effect.void instead of Effect.succeed(undefined) or Effect.succeed(void 0)βœ“βœ“
missedPipeableOpportunityβž–πŸ”§Suggests using .pipe() for nested function callsβœ“βœ“
missingEffectServiceDependencyβž–Checks that Effect.Service dependencies satisfy all required layer inputsβœ“
nestedEffectGenYieldβž–Warns when yielding a nested bare Effect.gen inside an existing Effect generator contextβœ“βœ“
redundantSchemaTagIdentifierπŸ’‘πŸ”§Suggests removing redundant identifier argument when it equals the tag value in Schema.TaggedClass/TaggedError/TaggedRequestβœ“βœ“
schemaStructWithTagπŸ’‘πŸ”§Suggests using Schema.TaggedStruct instead of Schema.Struct with _tag fieldβœ“βœ“
schemaUnionOfLiteralsβž–πŸ”§Suggests combining multiple Schema.Literal calls in Schema.Union into a single Schema.Literalβœ“
serviceNotAsClassβž–πŸ”§Warns when Context.Service is used as a variable instead of a class declarationβœ“
strictBooleanExpressionsβž–Enforces boolean types in conditional expressions for type safetyβœ“βœ“
unnecessaryArrowBlockβž–πŸ”§Suggests using a concise arrow body when the block only returns an expressionβœ“βœ“
unnecessaryEffectGenπŸ’‘πŸ”§Suggests removing Effect.gen when it contains only a single return statementβœ“βœ“
unnecessaryFailYieldableErrorπŸ’‘πŸ”§Suggests yielding yieldable errors directly instead of wrapping with Effect.failβœ“βœ“
unnecessaryPipeπŸ’‘πŸ”§Removes pipe calls with no argumentsβœ“βœ“
unnecessaryPipeChainπŸ’‘πŸ”§Simplifies chained pipe calls into a single pipe callβœ“βœ“

βž– 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

Codegen Status

Codegen V3 V4 Notes
accessors ❌ ❌ Generate Service accessor methods from comment directive
annotate ❌ ❌ Generate type annotations from comment directive
typeToSchema ❌ ❌ Generate Schema from type alias comment directive

Rename Status

Rename V3 V4 Notes
keyStrings ❌ ❌ Extend rename to include key string literals in Effect classes

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-tsgo when a new release includes upstream tsgo fixes you need or new Effect diagnostics you want.
  • There is no need to track upstream tsgo releases separately β€” effect-tsgo is 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"
              }
            }
          }
        ]
      }
    ]
  }
}

About

TypeScript-go enhanced with the Effect LSP experience

Resources

License

Code of conduct

Contributing

Security policy

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors