TS
GO

TypeScript to Go

10 lessons

Progress0%
1Introduction: Transpiled to Compiled Binary2Type Systems: Structural Interfaces3Functions4Objects to Structs5Generics6Error Handling7Async to Goroutines8Ecosystem9Testing10Go Standard Library
All Mirror Courses
TS
GO
Error Handling
MirrorLesson 6 of 10
Lesson 6

Error Handling

Error Handling

Introduction

In this lesson, you'll learn about error handling in Go. Coming from TypeScript, you already have a foundation for understanding this concept. We'll build on that knowledge while highlighting the key differences.

Mirror Card
TS
From TypeScript:

In TypeScript, you're familiar with error handling.

GO
In Go:

Go has its own approach to error handling, which we'll explore step by step.

The Go Way

Let's see how Go handles this concept. Here's a typical example:

GO
Go Example
// Custom error type
type NotFoundError struct {
    ID int
}

func (e *NotFoundError) Error() string {
    return fmt.Sprintf("user %d not found", e.ID)
}

func getUser(id int) (*User, error) {
    user, ok := db[id]
    if !ok {
        return nil, &NotFoundError{ID: id}
    }
    return &user, nil
}

user, err := getUser(42)
if err != nil {
    var notFound *NotFoundError
    if errors.As(err, &notFound) {
        fmt.Println("Not found:", notFound.ID)
    }
}

Comparing to TypeScript

Here's how you might have written similar code in TypeScript:

TS
TypeScript (What you know)
class NotFoundError extends Error {
  constructor(public id: number) {
    super(`User ${id} not found`);
  }
}

async function getUser(id: number): Promise<User> {
  const user = await db.find(id);
  if (!user) throw new NotFoundError(id);
  return user;
}

try {
  const user = await getUser(42);
} catch (err) {
  if (err instanceof NotFoundError) {
    console.error("Not found:", err.id);
  }
}
Mirror Card
TS
From TypeScript:

You may be used to different syntax or behavior.

GO
In Go:

Go has no exceptions — errors are values returned as the last return value

Mirror Card
TS
From TypeScript:

You may be used to different syntax or behavior.

GO
In Go:

No try/catch — check err != nil after every call that can fail

Mirror Card
TS
From TypeScript:

You may be used to different syntax or behavior.

GO
In Go:

Custom errors implement the error interface (single method: Error() string)

Mirror Card
TS
From TypeScript:

You may be used to different syntax or behavior.

GO
In Go:

errors.As() unwraps error chains, like instanceof for errors

Step-by-Step Breakdown

1. Errors Are Values, Not Exceptions

Go has no exceptions. Functions return errors as the last return value. This forces explicit handling at every call site — no hidden control flow.

TS
TypeScript
try {
  const data = await riskyOperation();
} catch (e) {
  handleError(e);
}
GO
Go
data, err := riskyOperation()
if err != nil {
    handleError(err)
    return
}
Rule of Thumb
Never ignore err. If you must, use _ but add a comment explaining why.

2. Custom Error Types

Any type that implements the error interface (Error() string method) is an error. This is structural typing applied to errors.

TS
TypeScript
class ValidationError extends Error {
  constructor(public field: string) {
    super(`Invalid field: ${field}`);
  }
}
GO
Go
type ValidationError struct {
    Field string
}

func (e *ValidationError) Error() string {
    return "invalid field: " + e.Field
}

3. errors.As and errors.Is

errors.As() unwraps an error chain to find a specific type (like instanceof). errors.Is() checks if an error matches a specific sentinel value.

TS
TypeScript
if (err instanceof NotFoundError) { ... }
GO
Go
var notFound *NotFoundError
if errors.As(err, &notFound) {
    fmt.Println(notFound.ID)
}

// Check sentinel:
if errors.Is(err, ErrNotFound) { ... }

4. fmt.Errorf and Error Wrapping

fmt.Errorf with %w wraps an error with context. This creates a chain that errors.As/Is can traverse — like cause chains in Java or error wrapping in some TS libraries.

TS
TypeScript
throw new Error(`fetch failed: ${originalError.message}`);
GO
Go
if err != nil {
    return fmt.Errorf("getUser: %w", err) // wraps original
}
// Later, unwrap:
original := errors.Unwrap(wrappedErr)
Rule of Thumb
Wrap errors with context using fmt.Errorf and %w. The pattern: 'functionName: original error'.

Common Mistakes

When coming from TypeScript, developers often make these mistakes:

  • Go has no exceptions — errors are values returned as the last return value
  • No try/catch — check err != nil after every call that can fail
  • Custom errors implement the error interface (single method: Error() string)
Common Pitfall
Don't assume Go works exactly like TypeScript. While the concepts may be similar, the syntax and behavior can differ significantly.

Key Takeaways

  • Go has no exceptions — errors are returned as values, forcing explicit handling
  • Custom error types implement the error interface (Error() string)
  • errors.As() checks type, errors.Is() checks value — replace instanceof/equality
  • fmt.Errorf with %w wraps errors with context for error chains
Rule of Thumb
The best way to learn is by doing. Try rewriting some of your TypeScript code in Go to practice these concepts.
PreviousNext