@svnrnns/typed-expo-store
v1.0.0
Published
A lightweight, type-safe wrapper for [expo-secure-store](https://docs.expo.dev/versions/latest/sdk/securestore/) with optional **Zod** validation for React Native and Expo apps.
Readme
@svnrnns/typed-expo-store
A lightweight, type-safe wrapper for expo-secure-store with optional Zod validation for React Native and Expo apps.
Features
- Type Safety: Built for TypeScript with generic types
- Optional Zod Validation: Add schema validation when you need it
- Async & Sync API: Both sync and async methods available
- Namespace Support: Avoid key collisions with prefixed keys
- Expiration Support: Store values with a time-to-live (TTL)
- Biometric Support: Check if biometric authentication is available
- Fallback Values: Ensure a value of the expected type is always retrieved
Installation
npm install @svnrnns/typed-expo-store zodImportant
While you don't need to install expo-secure-store directly for this package to work, it's required for your project if you want to enable custom plugins like Android Shared Preferences backup.
npm install expo-secure-store// app.json (expo)
"plugins": [
"expo-router",
["expo-secure-store", { "configureAndroidBackup": true }]
]Quick Start
Basic Usage
Create a TypedStore instance:
import { TypedStore } from "@svnrnns/typed-expo-store";
const store = new TypedStore();
// Set a value
store.setItem("theme", "dark");
await store.setItemAsync("user", { id: 1, name: "John" });
// Get a value (returns null if not found)
const theme = store.getItem("theme"); // 'dark' | null
const user = await store.getItemAsync<{ id: number; name: string }>("user");
// Get with fallback (returns fallback if not found)
const locale = store.getItem("locale", "en"); // 'en' if not found
// Remove a value
await store.removeItemAsync("theme");
// Check if key exists
store.itemExists("theme"); // boolean
await store.itemExistsAsync("theme"); // booleanWith Namespace
Use a namespace to prefix keys and avoid conflicts:
import { TypedStore } from "@svnrnns/typed-expo-store";
const store = new TypedStore("my-app");
store.setItem("theme", "dark");
// Stored as 'my-app:theme' in SecureStoreWith Zod Validation
Add a Zod schema as the third parameter for type-safe validation:
import { TypedStore } from "@svnrnns/typed-expo-store";
import { z } from "zod";
const store = new TypedStore();
// Get with Zod validation (returns fallback if not found or invalid)
const themeSchema = z.enum(["light", "dark"]);
const theme = store.getItem("theme", "light", themeSchema);
// Returns 'light' if key 'theme' is not found or fails validation
// Async version
const userSchema = z.object({ id: z.number(), name: z.string() });
const user = await store.getItemAsync("user", { id: 0, name: "" }, userSchema);With Expiration
Set values with a time-to-live (TTL) in milliseconds:
import { TypedStore } from "@svnrnns/typed-expo-store";
const store = new TypedStore();
// Expires in 1 hour
await store.setItemWithExpiration("token", "xxxx", 3600000);Standalone Functions
You can also import standalone functions:
import {
getItem,
getItemAsync,
setItem,
setItemAsync,
setItemWithExpiration,
itemExists,
itemExistsAsync,
removeItemAsync,
} from "@svnrnns/typed-expo-store";Examples
Store arrays or complex objects with Zod validation:
import { TypedStore } from "@svnrnns/typed-expo-store";
import { z } from "zod";
const store = new TypedStore();
await store.setItemAsync("filters", ["desc", "price"]);
const schema = z.array(z.string());
const filters = await store.getItemAsync("filters", [], schema);
// Returns ['desc', 'price'] or [] if invalidAPI Reference
TypedStore
| Method | Signature | Description |
| ------------------------------- | ------------------------------------------------------------- | ----------------------------------------------------- |
| setItem | setItem<T>(key: string, value: T): void | Stores a value (sync). |
| setItemAsync | setItemAsync<T>(key: string, value: T): Promise<void> | Stores a value (async). |
| setItemWithExpiration | setItemWithExpiration<T>(key, value, ttl): Promise<void> | Stores a value that expires after ttl ms. |
| getItem | getItem<T>(key: string): T \| null | Retrieves a value (sync). Returns null if not found. |
| getItem | getItem<T>(key: string, fallback: T): T | Retrieves a value with fallback (sync). |
| getItem | getItem<T>(key: string, fallback: T, schema: ZodType<T>): T | Retrieves a value with Zod validation (sync). |
| getItemAsync | getItemAsync<T>(key: string): Promise<T \| null> | Retrieves a value (async). Returns null if not found. |
| getItemAsync | getItemAsync<T>(key: string, fallback: T): Promise<T> | Retrieves a value with fallback (async). |
| getItemAsync | getItemAsync<T>(key, fallback, schema): Promise<T> | Retrieves a value with Zod validation (async). |
| removeItemAsync | removeItemAsync(key: string): Promise<void> | Removes a key (async). |
| itemExists | itemExists(key: string): boolean | Checks if a key exists (sync). |
| itemExistsAsync | itemExistsAsync(key: string): Promise<boolean> | Checks if a key exists (async). |
| getNamespace | getNamespace(): string \| undefined | Gets the current namespace. |
| setNamespace | setNamespace(namespace: string): void | Sets a new namespace. |
| canUseBiometricAuthentication | canUseBiometricAuthentication(): boolean | Checks if biometric auth is available. |
| static isAvailableAsync | isAvailableAsync(): Promise<boolean> | Checks if SecureStore is available on device. |
MIT License © 2025
