Skip to main content

操作文档和条目

¥Manipulating documents and entries

本指南将探讨用于在 Strapi v5 应用中操作文档和条目的 TypeScript 模式,包括如何利用 Strapi 的 UIDData 命名空间安全地与通用和已知实体类型交互。如果你正在开发基于 TypeScript 的 Strapi 项目,掌握这些方法将帮助你充分利用类型安全和代码完成,确保与应用内容和组件进行稳健、无错误的交互。

¥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.

☑️ Prerequisites
  • Strapi 应用:Strapi v5 应用。如果你没有,请按照 documentation 开始。

    ¥Strapi Application: A Strapi v5 application. If you don't have one, follow the documentation to get started.

  • TypeScript:确保在你的 Strapi 项目中设置了 TypeScript。你可以按照 Strapi 的 官方指南 来配置 TypeScript。

    ¥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

UID 命名空间包含表示应用中可用资源的字面量联合。

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

import type { UID } from '@strapi/strapi';
  • UID.ContentType 表示应用中每个内容类型标识符的联合

    ¥UID.ContentType represents a union of every content-type identifier in the application

  • UID.Component 表示应用中每个组件标识符的联合

    ¥UID.Component represents a union of every component identifier in the application

  • UID.Schema 表示应用中每个模式(内容类型或组件)标识符的联合

    ¥UID.Schema represents a union of every schema (content-type or component) identifier in the application

  • 还有其他...

    ¥And others...


Strapi 提供了一个 Data 命名空间,其中包含几个用于实体表示的内置类型。

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

import type { Data } from '@strapi/strapi';
  • Data.ContentType 表示 Strapi 文档对象

    ¥Data.ContentType represents a Strapi document object

  • Data.Component 表示 Strapi 组件对象

    ¥Data.Component represents a Strapi component object

  • Data.Entity 表示文档或组件

    ¥Data.Entity represents either a document or a component

实体的类型定义和 UID 均基于为你的应用生成的架构类型。

¥Both the entities' type definitions and UIDs are based on the generated schema types for your application.

如果出现不匹配或错误,你始终可以 重新生成类型

¥In case of a mismatch or error, you can always regenerate the types.

:::

用法

¥Usage

通用实体

¥Generic entities

处理通用数据时,建议使用 Data 类型的非参数化形式。

¥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;
// ...
// }
}
⚠️ 警告

在前面的示例中,document 的解析属性是每个内容类型所共有的属性。

¥In the preceding example, the resolved properties for document are those common to every content-type.

必须使用类型保护手动检查其他属性。

¥Other properties have to be checked manually using type guards.

if ('my_prop' in document) {
return document.my_prop;
}

通用组件

¥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

操作已知实体时,可以参数化 Data 类型以获得更好的类型安全性和代码完成。

¥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

使用类型的第二个参数 (TKeys),可以获得实体的子集。

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

type Credentials = Data.ContentType<'api::acount.acount', '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.

在下面的示例中,uid 类型在使用时推断为 T,并用作 document 的类型参数。

¥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}"`);
}
}
}

调用函数时,document 类型需要与给定的 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'>