Documents
documents-and-entries
documents-and-entries
Type
External
Status
Published
Created
Mar 5, 2026
Updated
Mar 5, 2026

Manipulating documents and entries with a TypeScript-based project#

This guide will explore TypeScript patterns for manipulating documents and entries in a Strapi v5 application, including how to leverage Strapi's UID and Data namespaces to interact with both generic and known entity types safely. If you're working on a TypeScript-based Strapi project, mastering these approaches will help you take full advantage of type safety and code completion, ensuring robust, error-free interactions with your application’s content and components.

  • Strapi Application: A Strapi v5 application. If you don't have one, follow the documentation to get started.
  • TypeScript: Ensure TypeScript is set up in your Strapi project. You can follow Strapi's official guide on configuring TypeScript.
  • Generated Types: Application types have been generated and are accessible.

Type Imports#

The UID namespace contains literal unions representing the available resources in the application.

import type { UID } from '@strapi/strapi';
  • UID.ContentType represents a union of every content-type identifier in the application
  • UID.Component represents a union of every component identifier in the application
  • UID.Schema represents a union of every schema (content-type or component) identifier in the application
  • And others...

Strapi provides a Data namespace containing several built-in types for entity representation.

import type { Data } from '@strapi/strapi';
  • Data.ContentType represents a Strapi document object
  • Data.Component represents a Strapi component object
  • Data.Entity represents either a document or a component

Usage#


Generic entities#

When dealing with generic data, it is recommended to use non-parametrized forms of the Data types.

Generic documents#

async function save(name: string, document: Data.ContentType) {
  await writeCSV(name, document);
  // ^ {
  // id: Data.ID;
  // documentId: string;
  // createdAt?: DateTimeValue;
  // updatedAt?: DateTimeValue;
  // publishedAt?: DateTimeValue;
  // ...
  // }
}

Generic components#

function renderComponent(parent: Node, component: Data.Component) {
  const elements: Element[] = [];
  const properties = Object.entries(component);

  for (const [name, value] of properties) {
    // ^ ^
    // string any
    const paragraph = document.createElement('p');

    paragraph.textContent = `Key: ${name}, Value: ${value}`;

    elements.push(paragraph);
  }

  parent.append(...elements);
}

Known entities#

When manipulating known entities, it is possible to parametrize Data types for better type safety and code completion.

Known documents#

const ALL_CATEGORIES = ['food', 'tech', 'travel'];

function validateArticle(article: Data.ContentType<'api::article.article'>) {
  const { title, category } = article;
  // ^? ^?
  // string Data.ContentType<'api::category.category'>

  if (title.length < 5) {
    throw new Error('Title too short');
  }

  if (!ALL_CATEGORIES.includes(category.name)) {
    throw new Error(`Unknown category ${category.name}`);
  }
}

Known components#

function processUsageMetrics(
  id: string,
  metrics: Data.Component<'app.metrics'>
) {
  telemetry.send(id, { clicks: metrics.clicks, views: metrics.views });
}

Advanced use cases#


Entities subsets#

Using the types' second parameter (TKeys), it is possible to obtain a subset of an entity.

type Credentials = Data.ContentType<'api::account.account', 'email' | 'password'>;
// ^? { email: string; password: string }
type UsageMetrics = Data.Component<'app.metrics', 'clicks' | 'views'>;
// ^? { clicks: number; views: number }

Type argument inference#

It is possible to bind and restrict an entity type based on other function parameters.

In the following example, the uid type is inferred upon usage as T and used as a type parameter for the document.

import type { UID } from '@strapi/strapi';

function display<T extends UID.ContentType>(
  uid: T,
  document: Data.ContentType<T>
) {
  switch (uid) {
    case 'api::article.article': {
      return document.title;
      // ^? string
      // ^? Data.ContentType<'api::article.article'>
    }
    case 'api::category.category': {
      return document.name;
      // ^? string
      // ^? Data.ContentType<'api::category.category'>
    }
    case 'api::account.account': {
      return document.email;
      // ^? string
      // ^? Data.ContentType<'api::account.account'>
    }
    default: {
      throw new Error(`unknown content-type uid: "${uid}"`);
    }
  }
}

When calling the function, the document type needs to match the given uid.

declare const article: Data.Document<'api::article.article'>;
declare const category: Data.Document<'api::category.category'>;
declare const account: Data.Document<'api::account.account'>;

display('api::article.article', article);
display('api::category.category', category);
display('api::account.account', account);
// ^ ✅

display('api::article.article', category);
// ^ Error: "category" is not assignable to parameter of type ContentType<'api::article.article'>