Typescript
This is a guide on how to use Dexie with Typescript using Dexie 4 - a little more lightweight than the old docs by utilizing new features in 4.0. Since Dexie 4 is practically backward compatible, you may also still follow the old Typescript docs if your prefer to do so.
Install dexie
Typings are part of the npm package so there’s no need to for any @types library.
npm install dexie
Like all other npm packages, dexie can also be installed using yarn or pnpm as alternatives to npm.
Simplest Typescript Example
If you are storing plain data and just want the a minimal get-started code in a single module. You can extend this sample with additional tables and corresponding interfaces:
db.ts
import Dexie, { type EntityTable } from 'dexie';
interface Friend {
id: number; // This prop will be used as primary key (see below)
name: string;
age: number;
}
const db = new Dexie('FriendsDatabase') as Dexie & {
friends: EntityTable<Friend, 'id'>
};
// Schema declaration:
db.version(1).stores({
friends: '++id, name, age' // primary key "id" (for the runtime!)
});
export type { Friend };
export { db };
See EntityTable
Example with Mapped Classes
Here’s an example of how to use mapped classes in Dexie 4. In this example, we split db.ts
into three different modules:
- db.ts - exports the singleton Dexie instance. To be imported wherever your db is needed.
- AppDB.ts - declaration of database schema
- Friend.ts - Entity class example. You could have muliple modules like this
db.ts
// db.ts
import AppDB from './AppDB';
export const db = new AppDB();
AppDB.ts
// AppDB.ts
import Dexie, { type EntityTable } from 'dexie';
import Friend from './Friend';
export default class AppDB extends Dexie {
friends!: EntityTable<Friend, 'id'>;
constructor() {
super('FriendsDB');
this.version(1).stores({
friends: '++id, name, age'
});
this.friends.mapToClass(Friend);
}
}
Friend.ts
// Friend.ts
import { Entity } from 'dexie';
import type AppDB from './AppDB';
export default class Friend extends Entity<AppDB> {
id!: number;
name!: string;
age!: number;
// example method that access the DB:
async birthday() {
// this.db is inherited from Entity<AppDB>:
await this.db.friends.update(this.id, (friend) => ++friend.age);
}
}
Usage examples
React component
import { db } from './db';
import { useLiveQuery } from 'dexie-react-hooks';
function MyReactComponent() {
const friends = useLiveQuery(() => db.friends.toArray());
return (
<ul>
{friends?.map((f) => (
<li key={f.id}>
{f.name}, {f.age}
</li>
))}
</ul>
);
}
Plain Typescript
import { db } from './db';
async function addFriend(name: string, age: number) {
await db.friends.add({ name, age });
}
async function updateFriend(id: number, updates: Partial<Friend>) {
await db.friends.update(id, { ...updates });
}
async function deleteFriend(id: number) {
await db.friends.delete(id);
}
Example with Dexie Cloud
Synced tables have a few more properties that, similar to auto-generated primary keys, are optional on insert but “required”/mandatory on all instances returned from db queries: owner
and realmId
. DexieCloudTable is therefore a better helper type to use for synced tables with dexie-cloud-addon.
AppDB.ts - Dexie Cloud version
import Dexie from 'dexie';
import dexieCloud, { type DexieCloudTable } from 'dexie-cloud-addon';
import Friend from './Friend';
export default class AppDB extends Dexie {
friends!: DexieCloudTable<Friend, 'id'>;
constructor() {
super('FriendsDB', {
addons: [dexieCloud]
});
this.version(1).stores({
friends: '@id, name, age'
});
this.friends.mapToClass(Friend);
this.cloud.configure({
databaseUrl: 'https://xxxxxx.dexie.cloud'
// see https://dexie.org/cloud/docs/db.cloud.configure()
});
}
}
Friend.ts - Dexie Cloud version
import type AppDB from './AppDB';
export default class Friend extends Entity<AppDB> {
id!: string; // Primary key is string
name!: string;
age!: number;
owner!: string; // Dexie Cloud specific property
realmId!: string; // Dexie Cloud specific property
}
Usage examples - Dexie Cloud version
The usage is almost identical to the plain Dexie version. But this example will show how usePermissions can help to get information about access control.
React component
import { db } from './db';
import { useLiveQuery, usePermissions } from 'dexie-react-hooks';
import type { Friend } from './Friend'; // ...where class Friend is defined (see earlier on this page).
function MyReactComponent() {
const friends = useLiveQuery(() => db.friends.toArray());
return (
<ul>
{friends?.map((f) => (
<li key={f.id}>
<FriendComponent friend={f} />
</li>
))}
</ul>
);
}
function FriendComponent({ friend }: { friend: Friend }) {
const can = usePermissions(friend); // https://dexie.org/docs/dexie-react-hooks/usePermissions()
// This 'can' instance can be used to check whether access control would permit the current user to
// perform various actions. This information can be used to disable or hide fields and buttons.
// (See also https://dexie.org/cloud/docs/access-control)
return (
<>
Name: {friend.name} <br />
Age: {friend.age} <br />
Can I edit name?: {can.update('name') ? 'Yes!' : 'No!'} <br />
Can I edit age?: {can.update('age') ? 'Yes!' : 'No!'} <br />
Can I delete this friend?: {can.delete() ? 'Yes!' : 'No!'} <br />
</>
);
}
Plain Typescript
import { db } from './db';
async function addFriend(name: string, age: number) {
// Ok to leave out id, realmId and owner as they are all auto-generated:
await db.friends.add({ name, age });
}
async function updateFriend(id: string, updates: Partial<Friend>) {
await db.friends.update(id, { ...updates });
}
async function deleteFriend(id: string) {
await db.friends.delete(id);
}
Table of Contents
- API Reference
- Access Control in Dexie Cloud
- Add demo users
- Add public data
- Authentication in Dexie Cloud
- Best Practices
- Building Addons
- Collection
- Collection.and()
- Collection.clone()
- Collection.count()
- Collection.delete()
- Collection.desc()
- Collection.distinct()
- Collection.each()
- Collection.eachKey()
- Collection.eachPrimaryKey()
- Collection.eachUniqueKey()
- Collection.filter()
- Collection.first()
- Collection.keys()
- Collection.last()
- Collection.limit()
- Collection.modify()
- Collection.offset()
- Collection.or()
- Collection.primaryKeys()
- Collection.raw()
- Collection.reverse()
- Collection.sortBy()
- Collection.toArray()
- Collection.uniqueKeys()
- Collection.until()
- Compound Index
- Consistency in Dexie Cloud
- Consistent add() operator
- Consistent remove() operator
- Consistent replacePrefix() operator
- Consuming Dexie as a module
- Custom Emails in Dexie Cloud
- DBCore
- DBCoreAddRequest
- DBCoreCountRequest
- DBCoreCursor
- DBCoreDeleteRangeRequest
- DBCoreDeleteRequest
- DBCoreGetManyRequest
- DBCoreGetRequest
- DBCoreIndex
- DBCoreKeyRange
- DBCoreMutateRequest
- DBCoreMutateResponse
- DBCoreOpenCursorRequest
- DBCorePutRequest
- DBCoreQuery
- DBCoreQueryRequest
- DBCoreQueryResponse
- DBCoreRangeType
- DBCoreSchema
- DBCoreTable
- DBCoreTableSchema
- DBCoreTransaction
- DBCoreTransactionMode
- DBPermissionSet
- Deprecations
- Derived Work
- Design
- Dexie Cloud API
- Dexie Cloud API Limits
- Dexie Cloud Best Practices
- Dexie Cloud CLI
- Dexie Cloud Docs
- Dexie Cloud REST API
- Dexie Cloud Web Hooks
- Dexie Constructor
- Dexie.AbortError
- Dexie.BulkError
- Dexie.ConstraintError
- Dexie.DataCloneError
- Dexie.DataError
- Dexie.DatabaseClosedError
- Dexie.IncompatiblePromiseError
- Dexie.InternalError
- Dexie.InvalidAccessError
- Dexie.InvalidArgumentError
- Dexie.InvalidStateError
- Dexie.InvalidTableError
- Dexie.MissingAPIError
- Dexie.ModifyError
- Dexie.NoSuchDatabaseErrorError
- Dexie.NotFoundError
- Dexie.Observable
- Dexie.Observable.DatabaseChange
- Dexie.OpenFailedError
- Dexie.PrematureCommitError
- Dexie.QuotaExceededError
- Dexie.ReadOnlyError
- Dexie.SchemaError
- Dexie.SubTransactionError
- Dexie.Syncable
- Dexie.Syncable.IDatabaseChange
- Dexie.Syncable.IPersistentContext
- Dexie.Syncable.ISyncProtocol
- Dexie.Syncable.StatusTexts
- Dexie.Syncable.Statuses
- Dexie.Syncable.registerSyncProtocol()
- Dexie.TimeoutError
- Dexie.TransactionInactiveError
- Dexie.UnknownError
- Dexie.UnsupportedError
- Dexie.UpgradeError()
- Dexie.VersionChangeError
- Dexie.VersionError
- Dexie.[table]
- Dexie.addons
- Dexie.async()
- Dexie.backendDB()
- Dexie.close()
- Dexie.currentTransaction
- Dexie.debug
- Dexie.deepClone()
- Dexie.defineClass()
- Dexie.delByKeyPath()
- Dexie.delete()
- Dexie.derive()
- Dexie.events()
- Dexie.exists()
- Dexie.extend()
- Dexie.fakeAutoComplete()
- Dexie.getByKeyPath()
- Dexie.getDatabaseNames()
- Dexie.hasFailed()
- Dexie.ignoreTransaction()
- Dexie.isOpen()
- Dexie.js
- Dexie.name
- Dexie.on()
- Dexie.on.blocked
- Dexie.on.close
- Dexie.on.error
- Dexie.on.populate
- Dexie.on.populate-(old-version)
- Dexie.on.ready
- Dexie.on.storagemutated
- Dexie.on.versionchange
- Dexie.open()
- Dexie.override()
- Dexie.semVer
- Dexie.setByKeyPath()
- Dexie.shallowClone()
- Dexie.spawn()
- Dexie.table()
- Dexie.tables
- Dexie.transaction()
- Dexie.transaction()-(old-version)
- Dexie.use()
- Dexie.verno
- Dexie.version
- Dexie.version()
- Dexie.vip()
- Dexie.waitFor()
- DexieCloudOptions
- DexieError
- Docs Home
- Download
- EntityTable
- Export and Import Database
- Get started with Dexie in Angular
- Get started with Dexie in React
- Get started with Dexie in Svelte
- Get started with Dexie in Vue
- Hello World
- How To Use the StorageManager API
- Inbound
- IndexSpec
- Indexable Type
- IndexedDB on Safari
- Invite
- Member
- Migrating existing DB to Dexie
- MultiEntry Index
- PersistedSyncState
- Privacy Policy
- Promise
- Promise.PSD
- Promise.catch()
- Promise.finally()
- Promise.on.error
- Promise.onuncatched
- Questions and Answers
- Realm
- Releasing Dexie
- Road Map
- Road Map: Dexie 5.0
- Road Map: Dexie Cloud
- Role
- Run Dexie Cloud on Own Servers
- Sharding and Scalability
- Simplify with yield
- Support Ukraine
- SyncState
- Table
- Table Schema
- Table.add()
- Table.bulkAdd()
- Table.bulkDelete()
- Table.bulkGet()
- Table.bulkPut()
- Table.bulkUpdate()
- Table.clear()
- Table.count()
- Table.defineClass()
- Table.delete()
- Table.each()
- Table.filter()
- Table.get()
- Table.hook('creating')
- Table.hook('deleting')
- Table.hook('reading')
- Table.hook('updating')
- Table.limit()
- Table.mapToClass()
- Table.name
- Table.offset()
- Table.orderBy()
- Table.put()
- Table.reverse()
- Table.schema
- Table.toArray()
- Table.toCollection()
- Table.update()
- Table.where()
- The main limitations of IndexedDB
- Transaction
- Transaction.abort()
- Transaction.on.abort
- Transaction.on.complete
- Transaction.on.error
- Transaction.table()
- Tutorial
- Typescript
- Typescript (old)
- Understanding the basics
- UserLogin
- Version
- Version.stores()
- Version.upgrade()
- WhereClause
- WhereClause.above()
- WhereClause.aboveOrEqual()
- WhereClause.anyOf()
- WhereClause.anyOfIgnoreCase()
- WhereClause.below()
- WhereClause.belowOrEqual()
- WhereClause.between()
- WhereClause.equals()
- WhereClause.equalsIgnoreCase()
- WhereClause.inAnyRange()
- WhereClause.noneOf()
- WhereClause.notEqual()
- WhereClause.startsWith()
- WhereClause.startsWithAnyOf()
- WhereClause.startsWithAnyOfIgnoreCase()
- WhereClause.startsWithIgnoreCase()
- db.cloud.configure()
- db.cloud.currentUser
- db.cloud.currentUserId
- db.cloud.events.syncComplete
- db.cloud.invites
- db.cloud.login()
- db.cloud.logout()
- db.cloud.options
- db.cloud.permissions()
- db.cloud.persistedSyncState
- db.cloud.roles
- db.cloud.schema
- db.cloud.sync()
- db.cloud.syncState
- db.cloud.userInteraction
- db.cloud.usingServiceWorker
- db.cloud.version
- db.cloud.webSocketStatus
- db.members
- db.realms
- db.roles
- db.syncable.connect()
- db.syncable.delete()
- db.syncable.disconnect()
- db.syncable.getOptions()
- db.syncable.getStatus()
- db.syncable.list()
- db.syncable.on('statusChanged')
- db.syncable.setFilter()
- dexie-cloud-addon
- dexie-react-hooks
- liveQuery()
- unhandledrejection-event
- useLiveQuery()
- useObservable()
- usePermissions()