使用基于 TypeScript 的项目操作文档和条目
🌐 Manipulating documents and entries with a TypeScript-based project
Page summary:在 Strapi v5 TypeScript 项目中安全地操作文档和条目,使用
UID和Data命名空间以确保类型安全,同时支持通用和已知实体类型的操作,并提供代码补全功能。🌐 Safely manipulate documents and entries in Strapi v5 TypeScript projects using the
UIDandDatanamespaces for type safety, enabling both generic and known entity type operations with code completion.
本指南将探讨在 Strapi v5 应用中操作文档和条目的 TypeScript 模式,包括如何利用 Strapi 的 UID 和 Data 命名空间安全地与通用和已知的实体类型进行交互。如果你正在开发基于 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.
类型导入
🌐 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.Component表示应用中每 个组件标识符的联合UID.Schema表示应用中每个模式(内容类型或组件)标识符的联合- 等等...
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.Component代表一个 Strapi 组件对象Data.Entity表示文档或组件
实体的类型定义和 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::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.
在以下示例中,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'>