Skip to main content

Overview

Type guard method that checks if a Result is an Err variant. Returns true if the Result contains an error value.

Signature

class Result<T, E> {
  isErr(): this is Err<T, E>
}
Returns: boolean - true if the Result is Err, false if it’s Ok

Usage

Basic error checking

import { ok, err } from 'neverthrow'

const success = ok(42)
const failure = err('Something went wrong')

if (failure.isErr()) {
  console.error('Error:', failure.error)
  // TypeScript knows this is Err<number, string>
  const errorMsg: string = failure.error
}

if (success.isErr()) {
  // This block won't execute
  console.error('This won\'t print')
}

Type narrowing

function handleResult(result: Result<Data, ApiError>) {
  if (result.isErr()) {
    // TypeScript narrows the type to Err<Data, ApiError>
    const error = result.error  // Type: ApiError
    logError(error)
    return null
  }
  
  // TypeScript knows result is Ok here
  return result.value  // Type: Data
}

Early error returns

function processData(result: Result<Data, string>): Data {
  if (result.isErr()) {
    throw new Error(result.error)
  }
  
  // TypeScript knows result is Ok here
  return result.value
}

Error recovery

const result = fetchData()

if (result.isErr()) {
  console.warn('Primary fetch failed:', result.error)
  // Try fallback
  const fallback = fetchFromCache()
  if (fallback.isErr()) {
    console.error('Fallback also failed:', fallback.error)
    return defaultData
  }
  return fallback.value
}

return result.value

Collecting errors

const results: Result<number, string>[] = [
  ok(1),
  err('error 1'),
  ok(2),
  err('error 2')
]

const errors = results
  .filter(r => r.isErr())
  .map(r => r.error)

// errors is ['error 1', 'error 2']

Type guard behavior

isErr() is a TypeScript type guard. After checking isErr(), TypeScript automatically narrows the type to Err<T, E>, giving you access to .error.
const result: Result<string, number> = err(404)

// Before isErr() check
result.error  // ❌ TypeScript error: Property 'error' doesn't exist on Result

if (result.isErr()) {
  // After isErr() check
  result.error  // ✅ TypeScript knows this is safe - returns 404
}

Common patterns

Guard clause pattern

function doSomething(result: Result<User, Error>): void {
  // Guard clause - handle error early
  if (result.isErr()) {
    notifyUser(result.error)
    return
  }
  
  // Continue with success path
  const user = result.value
  processUser(user)
}

Negation pattern

// Using isErr with negation
if (!result.isErr()) {
  // result is Ok
  console.log(result.value)
}

// More idiomatic: use isOk instead
if (result.isOk()) {
  console.log(result.value)
}

Comparison with other patterns

isErr vs match

// Using isErr - imperative style
if (result.isErr()) {
  return handleError(result.error)
}
return processValue(result.value)

// Using match - functional style  
return result.match(
  value => processValue(value),
  error => handleError(error)
)

isErr vs mapErr

// Using isErr to transform errors
if (result.isErr()) {
  const newError = transformError(result.error)
  return err(newError)
}
return result

// Using mapErr - more concise
return result.mapErr(transformError)

When to use

  • ✅ When you need to handle errors immediately
  • ✅ When using guard clauses for early returns
  • ✅ When integrating with existing imperative code
  • ✅ When collecting or filtering errors from arrays
  • ❌ When transforming errors → use mapErr() instead
  • ❌ When recovering from errors → use orElse() instead

isOk

Check if Result is an Ok variant

mapErr

Transform error values

Build docs developers (and LLMs) love