SDK
Packages
Core

Core SDK

The SDK Core package provides foundational types essential to the broader SDK ecosystem, primarily serving internal packages. It's designed to ensure consistency and facilitate type safety across the SDK.

Installation

To install this package, you need to have access to the private @sdk npm scope.

To integrate the SDK Core package into your project, use the following command with your preferred package manager:

npm install @sdk/core

This will add the core functionality required for working with other SDK packages.

Core Types

The Option Type

The Option type is inspired by the concept from functional programming languages. It represents a container that might hold a value (Some) or might not hold any value (None), effectively encapsulating the presence or absence of a value.

Constructors and Methods:

  • Option.Value(value): Creates an Option containing a value.
  • Option.None(): Creates an Option representing the absence of a value.
  • Option.isSome(option): Determines if an Option contains a value.
  • Option.unwrap(option): Extracts the value from an Option. Throws an error if the Option is None.
  • Option.unwrapOr(option, defaultValue): Extracts the value from an Option, returning defaultValue if the Option is None.

Examples:

import { Option } from '@sdk/core';
 
// Creating an Option with a value
const tokenOption = Option.Value('_AB5YaWdFnulJSC_qFCbX');
console.log(Option.isSome(tokenOption)); // true
console.log(Option.unwrap(tokenOption)); // _AB5YaWdFnulJSC_qFCbX
 
// Creating an Option without a value
const nothing = Option.None();
console.log(Option.isSome(nothing)); // false
console.log(Option.unwrapOr(nothing, '')); // ""
 
// Attempting to unwrap a None option will throw an error
try {
  console.log(Option.unwrap(nothing)); // This will throw
} catch (error) {
  console.error('Error:', error.message);
}

By leveraging the Option type, developers can more explicitly handle the presence or absence of values, reducing the risk of runtime errors related to undefined or null values. This approach enhances code clarity and reliability, especially in complex applications.

The Result Type

In the SDK Core package, the Result type is a powerful abstraction that represents a computation that may either result in a value or an error. This type is inspired by similar constructs in functional programming languages and is designed to enhance error handling and type safety in TypeScript applications.

The Result type is a generic union type that can contain either a value (Ok) or an error (Err), along with a boolean flag (ok) indicating the state. This design allows for expressive and safe error handling, making it clear when a function's return value needs to be checked for success or failure.

Constructors and Methods

  • Result.Ok(value): Creates a Result instance representing a successful outcome with a value.
  • Result.Err(error): Creates a Result instance representing a failure outcome with an error.
  • Result.isOk(result): Checks if a Result instance represents a success.
  • Result.isErr(result): Checks if a Result instance represents an error.

Type Parameters

  • T: The type of the value contained in a successful Result.
  • E: The type of the error contained in a failed Result.

Examples

Creating a Successful Result
import { Result } from '@sdk/core';
 
const successfulResult = Result.Ok(42);
// Result is { ok: true, value: 42 }
 
console.log(Result.isOk(successfulResult)); // true
console.log(Result.isErr(successfulResult)); // false
Creating a Failed Result
import { Result } from '@sdk/core';
 
const failedResult = Result.Err('An error occurred');
// Result is { ok: false, error: 'An error occurred' }
 
console.log(Result.isOk(failedResult)); // false
console.log(Result.isErr(failedResult)); // true

Usage

The Result type is particularly useful in functions that might fail, allowing the caller to handle success and failure cases explicitly. This pattern encourages checking the result of operations and dealing with errors appropriately, thus avoiding unhandled exceptions and improving application robustness.

Handling Results

Handling a Result typically involves checking whether it is an Ok or an Err and then taking appropriate action.

function processResult(result: Result<number, string>) {
  if (Result.isOk(result)) {
    console.log(`Success with value: ${result.value}`);
  } else {
    console.error(`Failed with error: ${result.error}`);
  }
}
 
processResult(successfulResult); // Logs the value
processResult(failedResult); // Logs the error

Leveraging Typed Errors for Enhanced Error Handling

The true power of the Result type unfolds when the error type E is defined as a union of possible error types. By specifying a union type for errors, you can precisely control the range of errors that a function can return, enabling more granular error handling and improving the developer's ability to react to different error scenarios.

Advantages of Typed Errors
  • Precision: Clearly defines the set of errors that can be expected, making functions easier to use and handle.
  • Autocompletion and Type Checking: Takes full advantage of TypeScript's type system, including autocompletion and compile-time type checking for error handling code.
  • Documentation: Serves as self-documenting code, indicating to developers what errors to expect and handle.
Example: Typed Errors with Union Types

Consider a scenario where a function can fail due to several distinct errors. By defining these errors as a union type, you can create more descriptive and safer error handling paths.

import { Result } from '@sdk/core';
 
// Define possible errors as a union type
type NetworkError = { type: 'network'; message: string };
type ValidationError = { type: 'validation'; field: string };
type DatabaseError = { type: 'database'; error: Error };
 
type MyError = NetworkError | ValidationError | DatabaseError;
 
// Function that might fail with a specific error
function fetchData(): Result<string, MyError> {
  // Example of a failure
  return Result.Err({ type: 'network', message: 'Network connection failed' });
}
 
// Handling the result with typed errors
const result = fetchData();
 
if (Result.isErr(result)) {
  switch (result.error.type) {
    case 'network':
      console.error(`Network error: ${result.error.message}`);
      break;
    case 'validation':
      console.error(`Validation error on field: ${result.error.field}`);
      break;
    case 'database':
      console.error(`Database error: ${result.error.error.message}`);
      break;
    default:
      console.error('Unknown error occurred');
  }
} else {
  console.log(`Data fetched successfully: ${result.value}`);
}