Skip to main content

TypeScript

The Easy React Native SDK is built with TypeScript and provides comprehensive type definitions for all APIs, components, and data structures.

Installation

TypeScript types are included with the package - no separate @types package is needed:

npm install @easylabs/react-native

Type Imports

Import types alongside your components:

import {
EasyProvider,
useEasy,
CardNumberElement,
} from "@easylabs/react-native";

// Import types
import type {
CreateCustomer,
CustomerData,
CreateCheckout,
CheckoutSessionData,
ApiResponse,
} from "@easylabs/react-native";

Component Types

EasyProvider

interface EasyProviderProps {
apiKey: string;
__dev?: boolean;
children: React.ReactNode;
}

Form Elements

interface CardNumberElementProps {
btRef: RefObject<ICardNumberElement>;
placeholder?: string;
style?: StyleProp<ViewStyle>;
editable?: boolean;
onFocus?: () => void;
onBlur?: () => void;
}

interface CardExpirationDateElementProps {
btRef: RefObject<ICardExpirationDateElement>;
placeholder?: string;
style?: StyleProp<ViewStyle>;
editable?: boolean;
onFocus?: () => void;
onBlur?: () => void;
}

interface CardVerificationCodeElementProps {
btRef: RefObject<ICardVerificationCodeElement>;
placeholder?: string;
style?: StyleProp<ViewStyle>;
editable?: boolean;
onFocus?: () => void;
onBlur?: () => void;
}

interface TextElementProps {
btRef: RefObject<ITextElement>;
placeholder?: string;
style?: StyleProp<ViewStyle>;
editable?: boolean;
onFocus?: () => void;
onBlur?: () => void;
}

API Types

Customer Types

interface CreateCustomer {
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;
tags?: Record<string, unknown>;
created_at: string;
updated_at: string;
}

Checkout Types

type CreateCheckout =
| CreateCheckoutNewCustomer
| CreateCheckoutExistingCustomer;

interface CreateCheckoutNewCustomer {
customer_creation: true;
customer_details: CreateCustomer;
source: PaymentSource;
line_items: LineItem[];
metadata?: Record<string, unknown>;
}

interface CreateCheckoutExistingCustomer {
customer_creation: false;
identity_id: string; // Customer ID
source: string | PaymentSource; // Payment instrument ID or new payment source
line_items: LineItem[];
metadata?: Record<string, unknown>;
}

interface CheckoutSessionData {
customer: CustomerData;
payment_instrument: PaymentInstrumentData;
transfer: TransferData;
order: OrderData;
}

Payment Types

type PaymentSource = PaymentCardParams | BankAccountParams;

interface PaymentCardParams {
type: "PAYMENT_CARD";
cardNumberElement: RefObject<ICardNumberElement>;
cardExpirationDateElement: RefObject<ICardExpirationDateElement>;
cardVerificationCodeElement: RefObject<ICardVerificationCodeElement>;
name?: string;
address?: Address;
}

interface BankAccountParams {
type: "BANK_ACCOUNT";
accountType: "CHECKING" | "SAVINGS";
routingElement: RefObject<ITextElement>;
accountElement: RefObject<ITextElement>;
name?: string;
}

Product Types

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

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

interface CreatePrice {
product_id: string;
unit_amount: number; // Amount in cents
currency: string;
recurring?: {
interval: "day" | "week" | "month" | "year";
interval_count: number;
};
active?: boolean;
description?: string;
metadata?: Record<string, unknown>;
}

interface PriceData {
id: string;
product_id: string;
unit_amount: number;
currency: string;
recurring?: {
interval: string;
interval_count: number;
};
active: boolean;
description?: string;
metadata?: Record<string, unknown>;
created_at: string;
updated_at: string;
}

Response Types

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

Usage Examples

Typed Customer Creation

import { useEasy } from "@easylabs/react-native";
import type {
CreateCustomer,
CustomerData,
ApiResponse,
} from "@easylabs/react-native";
import { Button, Alert } from "react-native";

function CreateCustomerButton() {
const { createCustomer } = useEasy();

const handleCreate = async () => {
const customerData: CreateCustomer = {
first_name: "John",
last_name: "Doe",
email: "[email protected]",
phone: "+1234567890",
personal_address: {
line1: "123 Main St",
city: "Anytown",
state: "CA",
postal_code: "12345",
country: "US",
},
};

try {
const response: ApiResponse<CustomerData> =
await createCustomer(customerData);

Alert.alert("Success", `Customer ID: ${response.data.id}`);
} catch (error) {
Alert.alert("Error", error.message);
}
};

return <Button title="Create Customer" onPress={handleCreate} />;
}

Typed Checkout

import { useEasy, CardNumberElement } from "@easylabs/react-native";
import type {
CreateCheckout,
CheckoutSessionData,
ApiResponse,
} from "@easylabs/react-native";
import { useRef, useState } from "react";
import { View, Button, Alert } from "react-native";

function CheckoutScreen() {
const { checkout } = useEasy();
const cardNumberRef = useRef(null);
const expiryRef = useRef(null);
const cvcRef = useRef(null);
const [loading, setLoading] = useState(false);

const handleCheckout = async () => {
setLoading(true);

const checkoutData: CreateCheckout = {
customer_creation: true,
customer_details: {
first_name: "Jane",
last_name: "Smith",
email: "[email protected]",
},
source: {
type: "PAYMENT_CARD",
cardNumberElement: cardNumberRef,
cardExpirationDateElement: expiryRef,
cardVerificationCodeElement: cvcRef,
name: "Jane Smith",
},
line_items: [{ price_id: "price_123", quantity: 1 }],
};

try {
const response: ApiResponse<CheckoutSessionData> =
await checkout(checkoutData);

Alert.alert(
"Success",
`Order ID: ${response.data.order.id}\nTransfer ID: ${response.data.transfer.id}`,
);
} catch (error) {
Alert.alert("Error", error.message);
} finally {
setLoading(false);
}
};

return (
<View>
{/* Form elements */}
<Button
title={loading ? "Processing..." : "Complete Purchase"}
onPress={handleCheckout}
disabled={loading}
/>
</View>
);
}

Typed Product Management

import { useEasy } from "@easylabs/react-native";
import type {
CreateProduct,
ProductData,
ApiResponse,
} from "@easylabs/react-native";
import { useState, useEffect } from "react";
import { FlatList, Text, View } from "react-native";

function ProductList() {
const { getProducts } = useEasy();
const [products, setProducts] = useState<ProductData[]>([]);

useEffect(() => {
loadProducts();
}, []);

const loadProducts = async () => {
try {
const response: ApiResponse<ProductData[]> = await getProducts({
limit: 20,
});

setProducts(response.data);
} catch (error) {
console.error("Failed to load products:", error);
}
};

return (
<FlatList
data={products}
keyExtractor={(item: ProductData) => item.id}
renderItem={({ item }) => (
<View>
<Text>{item.name}</Text>
<Text>{item.description}</Text>
<Text>{item.active ? "Active" : "Inactive"}</Text>
</View>
)}
/>
);
}

Generic Type Parameters

The SDK uses generic type parameters for flexible typing:

// Single item response
ApiResponse<CustomerData>;

// Array response
ApiResponse<ProductData[]>;

// Subscription response
ApiResponse<SubscriptionData>;

Type Guards

Use type guards to narrow union types:

import type { CreateCheckout } from "@easylabs/react-native";

function isNewCustomerCheckout(
checkout: CreateCheckout,
): checkout is CreateCheckoutNewCustomer {
return checkout.customer_creation === true;
}

// Usage
if (isNewCustomerCheckout(checkoutData)) {
// TypeScript knows this is CreateCheckoutNewCustomer
console.log(checkoutData.customer_details.email);
}

Utility Types

Use TypeScript utility types with SDK types:

import type { CreateCustomer, CustomerData } from "@easylabs/react-native";

// Partial update
type UpdateCustomer = Partial<CreateCustomer>;

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

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

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

Type Inference

Let TypeScript infer types when possible:

const { createCustomer, getProducts } = useEasy();

// Return types are automatically inferred
const customerResponse = await createCustomer({...}); // ApiResponse<CustomerData>
const productsResponse = await getProducts(); // ApiResponse<ProductData[]>

// Extract data with inferred types
const customer = customerResponse.data; // CustomerData
const products = productsResponse.data; // ProductData[]

Best Practices

1. Always Import Types

// ✅ Good
import type { CreateCustomer, CustomerData } from "@easylabs/react-native";

// ❌ Avoid
import { CreateCustomer, CustomerData } from "@easylabs/react-native";

2. Use Strict Mode

Enable strict mode in tsconfig.json:

{
"compilerOptions": {
"strict": true,
"strictNullChecks": true,
"strictFunctionTypes": true
}
}

3. Type Function Parameters

// ✅ Good
const handleCreate = async (data: CreateCustomer) => {
await createCustomer(data);
};

// ❌ Avoid
const handleCreate = async (data: any) => {
await createCustomer(data);
};

4. Type State Variables

// ✅ Good
const [products, setProducts] = useState<ProductData[]>([]);
const [loading, setLoading] = useState<boolean>(false);

// ❌ Avoid
const [products, setProducts] = useState([]);
const [loading, setLoading] = useState(false);

Next Steps