cast
Safe, predictable type conversion for Go — turn any value into the exact type you need without panics.
Repository Health
Technical Analysis
Cast is a small Go library for converting between value types safely and predictably. It exposes ToString, ToInt, ToBool, ToTime, and dozens of similar functions that accept any value — including untyped interface{} results from JSON, YAML, or TOML — and produce the target type, falling back to the zero value when the conversion is ambiguous. Each To___ function has a paired To___E variant that returns an explicit error instead of silently returning the zero value, so callers can opt into strict handling only where they need it.
Originally built for Hugo, where front matter arrives as loosely-typed data from YAML, TOML, or JSON sources, Cast is now used across the spf13 ecosystem and any Go codebase that needs to normalize dynamic, weakly-typed input into concrete types without hand-rolling type switches and strconv boilerplate.
What You Get
- To___ conversion functions - ToString, ToInt, ToBool, ToFloat64, ToTime, ToDuration and more, each returning the target type’s zero value on failed conversion
- To___E error-returning variants - identical conversions that return an explicit error instead of masking failures behind a zero value
- Generic ToE[T]/To[T] entry points - a single generic function dispatches to the right typed converter for any Basic-constrained type parameter
- Map and slice casting helpers - ToStringMapString, ToSlice, and related functions for converting collection types recursively
- Alias resolution via reflection - resolveAlias() unwraps named types (e.g. type MyInt int) back to their underlying kind so conversions work on custom types too
Common Use Cases
- Parsing YAML/TOML/JSON front matter - a static site generator like Hugo reads user-authored front matter as interface{} values and needs to coerce them into typed Go fields without crashing on unexpected input
- Normalizing configuration values - a CLI or config library accepts config values from flags, env vars, and files in different native types and casts them all to the type the caller expects
- Handling loosely-typed API responses - code unmarshaling JSON into map[string]interface{} needs to safely extract typed values (strings, numbers, times) from arbitrary keys
- Building small CLI tools - accepting user input as strings and converting to numeric or boolean flags without repetitive strconv boilerplate and panic-prone type assertions
Under The Hood
Architecture Cast is organized as a single flat package with one file per conversion domain — basic.go (bool/string), number.go (generic integer/unsigned/float parsing via shared parseInt/parseUint/parseFloat helpers), time.go (delegating to an internal/ subpackage for date-format detection), map.go and slice.go (collection casting), alias.go (reflection-based resolution of named types back to basic kinds), and indirect.go (pointer dereferencing). cast.go sits on top as the generic entry point, dispatching ToE[T Basic]/To[T] to the correct typed function via a type switch on the zero value of T. The bulk of the public API (the non-generic ToInt, ToBool, ToTime, etc. and their panic-safe non-E counterparts) is not hand-written but generated into zz_generated.go by a small generator/ program built on dave/jennifer’s Go AST builder, driven by a go:generate directive — a deliberate choice that keeps dozens of near-identical wrapper functions from drifting out of sync as the E-suffixed implementations evolve.
Tech Stack The runtime dependency surface is effectively empty: go.mod declares Go 1.21+ (for generics) and pulls in only stdlib packages (encoding/json, html/template, reflect, regexp, strconv, time) at runtime; the sole non-indirect require, frankban/quicktest, is exercised only from _test.go files, with go-cmp, kr/pretty, kr/text, and go-internal following as its transitive test-only dependencies. Code generation is handled by dave/jennifer in the separate generator/ module. Development tooling is reproducible via devenv.nix/devenv.lock and direnv, with a justfile exposing test (go test -race -shuffle on), lint (golangci-lint with errcheck, govet, ineffassign, misspell, unused), and fmt (gofmt/goimports/gci). CI runs the test suite on GitHub Actions on every push/PR to master, plus a separate scheduled OpenSSF Scorecard workflow that publishes a supply-chain security score.
Code Quality Every source file has a matching test.go counterpart (basic, number, time, map, slice, alias, indirect, cast, plus an internal number_internal_test.go for unexported helpers), and the test command runs with both -race and -shuffle on to catch ordering and concurrency bugs. Errors are handled explicitly and consistently: nearly every exported function has a To___E variant that returns a wrapped error (fmt.Errorf with %w) rather than swallowing failures, while the plain To__ variants intentionally trade the error for a documented zero-value fallback. golangci-lint enforces errcheck, govet, ineffassign, misspell, and unused across the codebase, and gofmt/goimports/gci keep formatting and import grouping consistent. No CONTRIBUTING.md exists, but exported identifiers carry GoDoc comments throughout.
API Design Cast’s public surface follows one consistent idiom across every conversion: a To<Type> function that never errors (returning the type’s zero value on failure) paired with a To<Type>E function that returns the same value plus an explicit error — letting callers opt into strict handling only where they need it, without forcing error-checking boilerplate everywhere. On top of the roughly twenty concrete conversion functions, a newer generic layer (ToE[T Basic], To[T Basic], ToNumberE[T Number]) lets callers write one generic call site instead of picking the right named function, using Go’s type-constraint interfaces (Basic, Number, integer, unsigned, float) to keep the generic dispatch exhaustive. The zero-value-on-failure versus explicit-error twin pattern is a well-established Go idiom rather than a novel one, but the code-generation step that derives the non-E functions from the E functions is a pragmatic way to keep a large, repetitive API surface correct as it grows.
Used by 4 apps in this directory
Apache Airflow
Data Engineering
Define, schedule, and monitor complex data workflows as Python code — with a powerful UI, 80+ provider integrations, and battle-tested scalability across thousands of production deployments.
Digger
Devops · Automation · Developer Tools
Run Terraform and OpenTofu natively inside your existing CI pipeline — no separate runners, no third-party secrets, no extra compute costs.
Ory Kratos
Authentication
API-first identity and user management that handles login, registration, MFA, and recovery so your application never has to.
PocketBase
Databases · Ecommerce · Authentication
Open Source realtime backend in 1 file — embedded SQLite, auth, file storage, and admin UI as a single Go binary.