go-go-try is a TypeScript utility library for error handling inspired by Go's error handling pattern. It provides a functional approach to try/catch operations by returning a tuple [error, value] instead of throwing exceptions.
- Name: go-go-try
- Version: 7.2.1
- License: MIT
- Repository: thelinuxlich/go-go-try
- Node.js Requirements: >= 16
- Zero runtime dependencies
- Dual package support (CommonJS and ESM)
- Full TypeScript support with precise type inference
- Support for sync/async functions, promises, and direct values
- Parallel execution utilities with optional concurrency control
- Tagged errors for discriminated union pattern matching
- Language: TypeScript 5.9.3
- Build Tool: pkgroll - A zero-config TypeScript package bundler
- Linter: Biome - Fast linter and formatter
- Test Framework: Vitest - Vite-native unit test framework
- Type Testing: @ark/attest - Runtime type assertions for TypeScript
- Git Hooks: Husky + lint-staged
.
├── src/
│ ├── index.ts # Main source file - exports all functions and types
│ └── index.test.ts # Comprehensive test suite with runtime and type tests
├── dist/ # Build output (generated by pkgroll)
│ ├── index.cjs # CommonJS build
│ ├── index.mjs # ES Module build
│ ├── index.d.cts # CommonJS type definitions
│ └── index.d.mts # ES Module type definitions
├── .github/workflows/
│ └── main.yml # CI configuration for GitHub Actions
├── .husky/
│ └── pre-commit # Git pre-commit hook (runs lint-staged)
├── .attest/ # Ark attest cache directory
├── package.json # Package configuration with dual CJS/ESM exports
├── tsconfig.json # TypeScript strict configuration
├── vitest.config.ts # Vitest configuration with type checking and coverage
├── setupVitest.ts # Vitest global setup for @ark/attest
└── README.md # User-facing documentation
# Build the project (generates dist/ with CJS, ESM, and type definitions)
npm run build
# Run linting with auto-fix
npm run lint
# Run the full test suite (build + lint + vitest)
npm test
# Run tests with coverage report
npm run test:coverageThe npm test script is a composite that:
- Builds the project
- Runs the linter
- Executes Vitest tests with type checking
- Linter: Biome is used for linting and formatting with default configuration (no biome.json present)
- Pre-commit: Husky runs
lint-stagedwhich lints all staged.tsfiles via Biome - Strict TypeScript: The
tsconfig.jsonenforces strict mode with additional checks:noUnusedLocals: truenoUnusedParameters: trueallowUnreachableCode: falsenoUncheckedIndexedAccess: truenoFallthroughCasesInSwitch: trueforceConsistentCasingInFileNames: true
Tests are co-located with source code in src/index.test.ts using Vitest.
- Runtime Tests: Standard unit tests verifying behavior using Vitest's
assertandtest - Type Tests: Using
@ark/attestto verify TypeScript type inference at runtime withattest<T>(value)
// Runtime test
import { assert, test } from 'vitest'
test('description', () => {
const result = goTry(() => 'value')
assert.equal(result[1], 'value')
})
// Type test
import { attest } from '@ark/attest'
test('types are correct', () => {
const result = goTry('value')
attest<Result<string, string>>(result)
})# Run all tests with type checking
npx vitest run
# Run tests in watch mode (during development)
npx vitest
# Run with coverage
npx vitest run --coverageCoverage is provided by @vitest/coverage-v8 with reporters: text, json, html, and lcov. Excluded paths:
node_modules/dist/**/*.test.tssetupVitest.ts
| Function | Description | Error Type |
|---|---|---|
goTry<T>(value) |
Returns [string | undefined, T | undefined] |
Error message string |
goTryRaw<T, E>(value, ErrorClass?) |
Returns [E | undefined, T | undefined] |
Raw Error object or tagged error |
goTryOr<T>(value, defaultValue) |
Returns [string | undefined, T] |
Error message with fallback default |
goTryAll<T>(items, options?) |
Parallel execution, returns [errors[], results[]] |
Error message strings |
goTryAllRaw<T>(items, options?) |
Parallel execution, returns [Error[], results[]] |
Raw Error objects |
All goTry* functions accept:
- Direct values
- Functions (sync or async)
- Promises
Result<E, T>: The tuple type[E \| undefined, T \| undefined]Success<T>:[undefined, T]Failure<E>:[E, undefined]TaggedError<T>: Interface for discriminated errors with_tagpropertyTaggedUnion<T>: Creates union type from multiple tagged error classesisSuccess(result): Type guard to check if result is successisFailure(result): Type guard to check if result is failuresuccess(value): Helper to create Success tuplefailure(error): Helper to create Failure tuple
The taggedError(tag) function creates error classes with a _tag property for discriminated union pattern matching:
const DatabaseError = taggedError('DatabaseError')
const err = new DatabaseError('connection failed')
// err._tag === 'DatabaseError'
// err instanceof Error === trueThe package supports both CommonJS and ESM consumers:
{
"type": "module",
"main": "./dist/index.cjs",
"module": "./dist/index.mjs",
"types": "./dist/index.d.mts",
"exports": {
"require": { "types": "./dist/index.d.cts", "default": "./dist/index.cjs" },
"import": { "types": "./dist/index.d.mts", "default": "./dist/index.mjs" }
}
}GitHub Actions workflow (.github/workflows/main.yml):
- Runs on every push and PR to
main/master - Tests against Node.js versions: 18, 20, 22
- Steps: checkout → setup Node → install → build → test with coverage
fail-fast: falseto see results for all Node versions- Coverage uploaded to Codecov (Node 22 only)
- Runs only on tag pushes (refs/tags/v*)
- Depends on successful test job
- Publishes to npm with provenance
- Requires
NPM_TOKENsecret
- Zero runtime dependencies - reduces supply chain attack surface
- Dev dependencies are locked via
package-lock.json - Uses
type: "module"for native ESM support - npm publishing uses provenance for supply chain security
- CI has minimal permissions (
contents: read,id-token: write)
- Make changes to
src/index.ts - Add/update tests in
src/index.test.ts - Run
npm testto verify build, lint, and tests pass - The CI will test against multiple Node.js versions on push
- To release: push a version tag (e.g.,
v7.2.1) to trigger npm publish
- Always run
npm testafter making changes to ensure build, lint, and tests pass - Type tests with
@ark/attestare as important as runtime tests - The library has zero dependencies - avoid adding any
- Maintain dual CJS/ESM compatibility when making changes
- Follow the existing function overload patterns for type inference
- Error handling should preserve the Go-style tuple return pattern
- Use
taggedError()for creating discriminated error types - The
goTryAllfunction supports both promise arrays and factory function arrays for lazy execution - When adding new functions, include both runtime tests and type tests with
attest()