Skip to main content

TypeScript Support

The Easy Node.js SDK is built with TypeScript and provides comprehensive type definitions for all APIs.

Installation

TypeScript types are included with the package:

npm install @easylabs/node

Basic Usage

import { createClient } from "@easylabs/node";
import type {
CreateCustomer,
CreateTransfer,
CreateProduct,
CustomerData,
TransferData,
ApiResponse,
} from "@easylabs/node";

const easy = await createClient({
apiKey: process.env.EASY_API_KEY!,
});

// All parameters are fully typed
const customerData: CreateCustomer = {
first_name: "John",
last_name: "Doe",
email: "[email protected]",
// TypeScript enforces correct types and required fields
};

// Return types are inferred
const result: Promise<ApiResponse<CustomerData>> =
easy.createCustomer(customerData);

// Response data is typed
result.then((response) => {
const customer = response.data; // Type: CustomerData
console.log(customer.id); // TypeScript knows all properties
});

Core Types

ApiResponse<T>

All API methods return this wrapper type:

interface ApiResponse<T> {
data: T;
status: number;
message?: string;
}

Customer Types

interface CreateCustomer {
first_name: string;
last_name: string;
email: string;
phone?: string;
personal_address?: Address;
tags?: Record<string, unknown>;
}

interface UpdateCustomer {
first_name?: string;
last_name?: string;
email?: string;
phone?: string;
personal_address?: Address;
tags?: Record<string, unknown>;
}

interface CustomerData {
id: string;
first_name: string;
last_name: string;
email: string;
phone?: string;
personal_address?: Address;
created_at: string;
updated_at: string;
tags?: Record<string, unknown>;
}

interface Address {
line1: string;
line2?: string;
city: string;
state: string;
postal_code: string;
country: string;
}

Payment Instrument Types

interface CreatePaymentInstrument {
type: "PAYMENT_CARD" | "BANK_ACCOUNT";
name: string;
identityId: string;
tokenId: string;
address?: Address;
accountType?: "CHECKING" | "SAVINGS";
attempt_bank_account_validation_check?: boolean;
tags?: Record<string, unknown>;
}

interface PaymentInstrumentData {
id: string;
type: "PAYMENT_CARD" | "BANK_ACCOUNT";
name: string;
identity_id: string;
created_at: string;
updated_at: string;
card_brand?: string;
card_last4?: string;
card_exp_month?: number;
card_exp_year?: number;
bank_name?: string;
account_last4?: string;
account_type?: "CHECKING" | "SAVINGS";
tags?: Record<string, unknown>;
}

Transfer Types

interface CreateTransfer {
amount: number;
currency: string;
source: string;
statement_descriptor?: string;
tags?: Record<string, unknown>;
}

interface TransferData {
id: string;
amount: number;
currency: string;
source: string;
statement_descriptor?: string;
state: "PENDING" | "SUCCEEDED" | "FAILED" | "CANCELED";
created_at: string;
updated_at: string;
tags?: Record<string, unknown>;
}

Product Types

interface CreateProduct {
name: string;
description?: string;
active?: boolean;
metadata?: Record<string, unknown>;
images?: string[];
url?: string;
}

interface ProductData {
id: string;
name: string;
description?: string;
active: boolean;
created_at: string;
updated_at: string;
metadata?: Record<string, unknown>;
images?: string[];
url?: string;
}

Price Types

interface CreatePrice {
product_id: string;
unit_amount: number;
currency: string;
recurring?: {
interval: "day" | "week" | "month" | "year";
interval_count: number;
};
active?: boolean;
description?: string;
}

interface PriceData {
id: string;
product_id: string;
unit_amount: number;
currency: string;
recurring?: {
interval: "day" | "week" | "month" | "year";
interval_count: number;
};
active: boolean;
description?: string;
created_at: string;
updated_at: string;
}

Checkout Types

interface CheckoutData {
customer_creation: boolean;
customer_details?: CreateCustomer;
identity_id?: string;
source: PaymentSource | string;
line_items: LineItem[];
metadata?: Record<string, unknown>;
}

interface PaymentSource {
type: "PAYMENT_CARD" | "BANK_ACCOUNT";
tokenId: string;
name: string;
}

interface LineItem {
price_id: string;
quantity: number;
}

interface OrderData {
id: string;
order_number: string;
customer_id: string;
total_cents: number;
currency: string;
state: string;
line_items: LineItem[];
created_at: string;
updated_at: string;
metadata?: Record<string, unknown>;
}

Type-Safe Functions

import { createClient } from "@easylabs/node";
import type { CreateCustomer, CustomerData, ApiResponse } from "@easylabs/node";

async function createCustomerSafely(
data: CreateCustomer,
): Promise<CustomerData> {
const easy = await createClient({
apiKey: process.env.EASY_API_KEY!,
});

const response: ApiResponse<CustomerData> = await easy.createCustomer(data);
return response.data;
}

// Usage
const customer = await createCustomerSafely({
first_name: "John",
last_name: "Doe",
email: "[email protected]",
});

// TypeScript knows customer is CustomerData
console.log(customer.id); // ✓ Valid
console.log(customer.invalidField); // ✗ TypeScript error

Generic Helper Functions

import type { ApiResponse } from "@easylabs/node";

async function handleApiCall<T>(
apiCall: () => Promise<ApiResponse<T>>,
): Promise<T | null> {
try {
const response = await apiCall();
return response.data;
} catch (error) {
console.error("API call failed:", error);
return null;
}
}

// Usage with type inference
const customer = await handleApiCall(() => easy.getCustomer("cust_123"));
// customer is CustomerData | null

Type Guards

function isSuccessfulResponse<T>(
response: ApiResponse<T> | { error: string },
): response is ApiResponse<T> {
return "data" in response && "status" in response;
}

// Usage
const response = await easy.createCustomer(data);

if (isSuccessfulResponse(response)) {
console.log("Success:", response.data.id);
} else {
console.error("Error:", response.error);
}

Extending Types

import type { CustomerData, CreateCustomer } from "@easylabs/node";

// Add custom properties
interface ExtendedCustomer extends CustomerData {
customField: string;
preferences: {
notifications: boolean;
theme: "light" | "dark";
};
}

// Custom create type
interface ExtendedCreateCustomer extends CreateCustomer {
referral_code?: string;
}

// Use in functions
async function createCustomerWithReferral(
data: ExtendedCreateCustomer,
): Promise<ExtendedCustomer> {
const { referral_code, ...customerData } = data;

const customer = await easy.createCustomer({
...customerData,
tags: {
...customerData.tags,
referral_code,
},
});

return {
...customer.data,
customField: "custom value",
preferences: {
notifications: true,
theme: "light",
},
};
}

Pagination Types

interface PaginationParams {
limit?: number;
offset?: number;
}

async function getAllCustomers(): Promise<CustomerData[]> {
const allCustomers: CustomerData[] = [];
let offset = 0;
const limit = 100;

while (true) {
const response = await easy.getCustomers({ limit, offset });
allCustomers.push(...response.data);

if (response.data.length < limit) {
break;
}

offset += limit;
}

return allCustomers;
}

Express with TypeScript

import express, { Request, Response, NextFunction } from "express";
import { createClient } from "@easylabs/node";
import type { CreateCustomer, CustomerData } from "@easylabs/node";

const app = express();
app.use(express.json());

const easy = await createClient({
apiKey: process.env.EASY_API_KEY!,
});

interface CreateCustomerRequest extends Request {
body: CreateCustomer;
}

app.post(
"/api/customers",
async (req: CreateCustomerRequest, res: Response) => {
try {
const customer: CustomerData = (await easy.createCustomer(req.body)).data;
res.status(201).json(customer);
} catch (error) {
res.status(400).json({ error: (error as Error).message });
}
},
);

Next.js with TypeScript

// app/api/customers/route.ts
import { NextRequest, NextResponse } from "next/server";
import { getEasyClient } from "@/lib/easy-client";
import type { CreateCustomer, CustomerData } from "@easylabs/node";

export async function POST(request: NextRequest) {
try {
const easy = await getEasyClient();
const body: CreateCustomer = await request.json();

const customer: CustomerData = (await easy.createCustomer(body)).data;

return NextResponse.json(customer, { status: 201 });
} catch (error) {
return NextResponse.json(
{ error: (error as Error).message },
{ status: 400 },
);
}
}

Type Utilities

import type { CustomerData, TransferData } from "@easylabs/node";

// Pick specific fields
type CustomerSummary = Pick<
CustomerData,
"id" | "email" | "first_name" | "last_name"
>;

// Make fields optional
type PartialCustomer = Partial<CustomerData>;

// Make fields required
type RequiredCustomer = Required<CustomerData>;

// Omit fields
type CustomerWithoutDates = Omit<CustomerData, "created_at" | "updated_at">;

Best Practices

  1. Always use explicit types for function parameters
  2. Use type inference for return values when possible
  3. Create custom types for domain-specific data
  4. Use type guards for runtime checks
  5. Leverage TypeScript's strict mode for better safety
// tsconfig.json
{
"compilerOptions": {
"strict": true,
"strictNullChecks": true,
"noImplicitAny": true,
"esModuleInterop": true
}
}