mirror of
https://github.com/strapi/strapi.git
synced 2025-08-18 05:37:10 +00:00
docs: update code formatting and minor text adjustments in type system documentation (#20186)
This commit is contained in:
parent
bdaafbbb3c
commit
01bf5cfbe4
@ -67,8 +67,8 @@ For instance, a string attribute will resolve to a primitive string in an entity
|
||||
|
||||
### Usage
|
||||
|
||||
import Tabs from '@theme/Tabs'
|
||||
import TabItem from '@theme/TabItem'
|
||||
import Tabs from '@theme/Tabs';
|
||||
import TabItem from '@theme/TabItem';
|
||||
|
||||
<Tabs>
|
||||
<TabItem value="public" label="Public" default>
|
||||
@ -89,22 +89,23 @@ declare const component: Schema.Component;
|
||||
|
||||
declare function processAnySchema(schema: Schema.Schema): void;
|
||||
|
||||
processAnySchema(schema); // ✅
|
||||
processAnySchema(schema); // ✅
|
||||
processAnySchema(contentType); // ✅
|
||||
processAnySchema(component); // ✅
|
||||
|
||||
declare function processContentTypeSchema(schema: Schema.ContentType): void;
|
||||
|
||||
processContentTypeSchema(schema); // ✅
|
||||
processContentTypeSchema(schema); // ✅
|
||||
processContentTypeSchema(contentType); // ✅
|
||||
processContentTypeSchema(component); // ❌ Error, a component schema is not assignable to a content-type schema
|
||||
|
||||
declare function processComponentSchema(schema: Schema.Component): void;
|
||||
|
||||
processComponentSchema(schema); // ✅
|
||||
processComponentSchema(schema); // ✅
|
||||
processComponentSchema(contentType); // ❌ Error, a content-type schema is not assignable to a component schema
|
||||
processComponentSchema(component); // ✅
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
<TabItem value="internal" label="Internal">
|
||||
Schema definitions exported from the `Struct` namespace defines the low level type representation of Strapi schemas.
|
||||
@ -112,6 +113,7 @@ Schema definitions exported from the `Struct` namespace defines the low level ty
|
||||
:::caution
|
||||
Those types can be useful when you want to validate other types against the base ones, but realistically, the public Schema types should almost always be preferred.
|
||||
:::
|
||||
|
||||
```typescript
|
||||
import type { Struct } from '@strapi/strapi';
|
||||
|
||||
@ -121,21 +123,22 @@ declare const component: Struct.ComponentSchema;
|
||||
|
||||
declare function processAnySchema(schema: Struct.Schema): void;
|
||||
|
||||
processAnySchema(schema); // ✅
|
||||
processAnySchema(schema); // ✅
|
||||
processAnySchema(contentType); // ✅
|
||||
processAnySchema(component); // ✅
|
||||
|
||||
declare function processContentTypeSchema(schema: Struct.ContentTypeSchema): void;
|
||||
|
||||
processContentTypeSchema(schema); // ✅
|
||||
processContentTypeSchema(schema); // ✅
|
||||
processContentTypeSchema(contentType); // ✅
|
||||
processContentTypeSchema(component); // ❌ Error, a component schema is not assignable to a content-type schema
|
||||
|
||||
declare function processComponentSchema(schema: Struct.ComponentSchema): void;
|
||||
|
||||
processComponentSchema(schema); // ✅
|
||||
processComponentSchema(schema); // ✅
|
||||
processComponentSchema(contentType); // ❌ Error, a content-type schema is not assignable to a component schema
|
||||
processComponentSchema(component); // ✅
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
</Tabs>
|
||||
|
@ -14,7 +14,6 @@ On this page, **a resource** is considered as **anything that can be identified
|
||||
This includes (but is not limited to) controllers, schema, services, policies, middlewares, etc...
|
||||
:::
|
||||
|
||||
|
||||
In the Type System, UIDs play a crucial role in referencing various resources (such as schema and entities) by attaching a unique identifier.
|
||||
|
||||
To put it simply, a UID is a unique (string) literal key used to identify, locate, or access a particular resource within the system.
|
||||
@ -26,6 +25,7 @@ This makes it the perfect tool to index type registries or to use as a type para
|
||||
### Format
|
||||
|
||||
A UID is composed of 3 different parts:
|
||||
|
||||
1. A namespace ([link](#1-namespaces))
|
||||
2. A separator ([link](#2-separators))
|
||||
3. A name ([link](#3-names))
|
||||
@ -46,7 +46,7 @@ Scoped namespaces are defined by a base name, followed by a separator (`::`) and
|
||||
In Strapi there are two of them:
|
||||
|
||||
| Name | Definition | Description |
|
||||
|--------|:-----------------:|------------------------------------------------------|
|
||||
| ------ | :---------------: | ---------------------------------------------------- |
|
||||
| API | `api::<scope>` | Represent a resource present in the `<scope>` API |
|
||||
| Plugin | `plugin::<scope>` | Represent a resource present in the `<scope>` plugin |
|
||||
|
||||
@ -57,7 +57,7 @@ These namespaces are used as a simple prefix and define the origin of a resource
|
||||
Strapi uses three of them to create UIDs
|
||||
|
||||
| Name | Definition | Description |
|
||||
|--------|:----------:|-------------------------------------------------------------------------------|
|
||||
| ------ | :--------: | ----------------------------------------------------------------------------- |
|
||||
| Strapi | `strapi` | Represent a resource present in the core of strapi |
|
||||
| Admin | `admin` | Represent a resource present in Strapi admin |
|
||||
| Global | `global` | Rarely used (_e.g. policies or middlewares_), it represents a global resource |
|
||||
@ -90,7 +90,7 @@ ContentType and Component are referring to both the related schema and entity.
|
||||
:::
|
||||
|
||||
| | ContentType | Component | Middleware | Policy | Controller | Service |
|
||||
|--------------------------|:------------------:|:------------------:|:------------------:|:------------------:|:------------------:|:------------------:|
|
||||
| ------------------------ | :----------------: | :----------------: | :----------------: | :----------------: | :----------------: | :----------------: |
|
||||
| `api::<scope>.<name>` | :white_check_mark: | :x: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: |
|
||||
| `plugin::<scope>.<name>` | :white_check_mark: | :x: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: |
|
||||
| `<category>.<name>` | :x: | :white_check_mark: | :x: | :x: | :x: | :x: |
|
||||
@ -141,6 +141,7 @@ fetch('api::article.article');
|
||||
fetch('admin::user');
|
||||
// ^ this should return a Data.Entity<'admin::user'>
|
||||
```
|
||||
|
||||
To do that, we'll need the function to be able to provide us with the current `uid` type based on usage.
|
||||
|
||||
```typescript
|
||||
@ -171,14 +172,15 @@ Let's add the possibility to select which fields we want to return for our entit
|
||||
```typescript
|
||||
import type { UID, Data, Schema } from '@strapi/types';
|
||||
|
||||
declare function fetch<
|
||||
T extends UID.ContentType,
|
||||
F extends Schema.AttributeNames<T>
|
||||
>(uid: T, fields: F[]): Data.ContentType<T>;
|
||||
declare function fetch<T extends UID.ContentType, F extends Schema.AttributeNames<T>>(
|
||||
uid: T,
|
||||
fields: F[]
|
||||
): Data.ContentType<T>;
|
||||
```
|
||||
|
||||
:::tip
|
||||
You may have noticed that we're using the inferred UID type (`T`) to reference both:
|
||||
|
||||
- An entity (`Data.Entity<T>`)
|
||||
- A schema (`Schema.AttributeNames<T>`)
|
||||
|
||||
|
@ -9,8 +9,8 @@ tags:
|
||||
toc_max_heading_level: 5
|
||||
---
|
||||
|
||||
import Tabs from '@theme/Tabs'
|
||||
import TabItem from '@theme/TabItem'
|
||||
import Tabs from '@theme/Tabs';
|
||||
import TabItem from '@theme/TabItem';
|
||||
|
||||
### Context
|
||||
|
||||
@ -108,6 +108,7 @@ Creating a new registry is as simple as exporting an indexed interface from the
|
||||
Let's declare the content-type schema registry.
|
||||
|
||||
It should accept:
|
||||
|
||||
- Content-type UIDs as keys
|
||||
- Content-type schemas as values
|
||||
|
||||
@ -130,7 +131,7 @@ We use low level types to define our index (`Internal`/`Struct`) to keep it as g
|
||||
To define `UID.ContentType`, we extract every key (`Internal.Registry.Keys`) from the public content-type registry (`Public.ContentTypeSchemas`) that matches with the base definition of a content-type UID (`Internal.UID.ContentType`).
|
||||
|
||||
```ts title="@strapi/types/uid.ts"
|
||||
import type { Internal, Public } from '@strapi/types'
|
||||
import type { Internal, Public } from '@strapi/types';
|
||||
|
||||
export type ContentType = Internal.Registry.Keys<
|
||||
Public.ContentTypeSchemas,
|
||||
@ -151,7 +152,7 @@ Since `UID.ContentType` (`TUID`) is [dynamically built based on actual keys](#ui
|
||||
:::
|
||||
|
||||
```ts title="@strapi/types/schema.ts"
|
||||
import type { UID, Public } from '@strapi/types'
|
||||
import type { UID, Public } from '@strapi/types';
|
||||
|
||||
export type ContentType<TUID extends UID.ContentType> = Public.ContentTypeSchemas[TUID];
|
||||
```
|
||||
@ -172,6 +173,7 @@ Remember to use dynamic type definitions (`UID`, `Data`, `Schema`) and not stati
|
||||
|
||||
:::info[Reminder]
|
||||
Registries are **indexed**, which means that:
|
||||
|
||||
- **When augmented** (_e.g. in users' applications_), they'll return **strongly typed values** that correspond to the defined types.
|
||||
- **When empty** (_e.g. in Strapi codebase_), they'll return **generic low level types** based on their index definition.
|
||||
|
||||
@ -183,6 +185,7 @@ Registries are **indexed**, which means that:
|
||||
const uid: UID.ContentType;
|
||||
// ^ 'api::article.article' | 'admin::user'
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
<TabItem value="empty" label="Empty">
|
||||
```ts
|
||||
@ -191,6 +194,7 @@ Registries are **indexed**, which means that:
|
||||
const uid: UID.ContentType;
|
||||
// ^ `admin::${string}` | `api::${string}.${string}` | `plugin::${string}.${string}` | `strapi::${string}`
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
</Tabs>
|
||||
:::
|
||||
@ -215,7 +219,7 @@ declare module '@strapi/strapi' {
|
||||
}
|
||||
}
|
||||
}
|
||||
````
|
||||
```
|
||||
|
||||
This will force every type that depends on the `Public.ContentTypeSchemas` registry to recognize `'api::article.article'` as the only valid UID and `ApiArticleArticle` the only valid schema.
|
||||
|
||||
@ -235,18 +239,20 @@ The process will generate type definitions based on the user application state (
|
||||
<TabItem value="manual" label="Manual Run">
|
||||
Generate the types once.
|
||||
|
||||
```shell title="my-app/"
|
||||
yarn strapi ts:generate-types
|
||||
```
|
||||
```shell title="my-app/"
|
||||
yarn strapi ts:generate-types
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
<TabItem value="dev" label="During Development">
|
||||
Start the application in dev mode, and generate types on every server restart.
|
||||
|
||||
Useful when working with the content-type builder.
|
||||
|
||||
```shell title="my-app/"
|
||||
yarn develop
|
||||
```
|
||||
```shell title="my-app/"
|
||||
yarn develop
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
</Tabs>
|
||||
|
||||
@ -277,40 +283,43 @@ declare module '@strapi/strapi' {
|
||||
|
||||
When coupling everything together, the end result is a TypeScript developer experience automatically adjusted to the current context.
|
||||
|
||||
<!-- prettier-ignore-start -->
|
||||
|
||||
<Tabs>
|
||||
<TabItem value="app" label="User Application">
|
||||
```ts title="my-app/src/index.ts"
|
||||
export default () => ({
|
||||
bootstrap() {
|
||||
strapi.findOne('ap');
|
||||
// ^ TypeScript will autocomplete with "api::article.article"
|
||||
<TabItem value="app" label="User Application">
|
||||
```ts title="my-app/src/index.ts"
|
||||
export default () => ({
|
||||
bootstrap() {
|
||||
strapi.findOne('ap');
|
||||
// ^ TypeScript will autocomplete with "api::article.article"
|
||||
|
||||
strapi.findOne('ad');
|
||||
// ^ TypeScript will autocomplete with "admin::user"
|
||||
strapi.findOne('ad');
|
||||
// ^ TypeScript will autocomplete with "admin::user"
|
||||
|
||||
strapi.findOne('api::blog.blog');
|
||||
// ^ Error, TypeScript will complain
|
||||
}
|
||||
})
|
||||
```
|
||||
</TabItem>
|
||||
<TabItem value="strapi" label="Strapi Codebase">
|
||||
```ts title="@strapi/strapi/document-service.ts"
|
||||
import type { UID } from '@strapi/types';
|
||||
|
||||
export const findOne<TUID extends UID.ContentType>(uid: TUID) {
|
||||
// ...
|
||||
strapi.findOne('api::blog.blog');
|
||||
// ^ Error, TypeScript will complain
|
||||
}
|
||||
})
|
||||
```
|
||||
</TabItem>
|
||||
<TabItem value="strapi" label="Strapi Codebase">
|
||||
```ts title="@strapi/strapi/document-service.ts"
|
||||
import type { UID } from '@strapi/types';
|
||||
|
||||
findOne('admin::foo');
|
||||
// ^ Valid, matches 'admin::${string}'
|
||||
export const findOne<TUID extends UID.ContentType>(uid: TUID) {
|
||||
// ...
|
||||
}
|
||||
|
||||
findOne('plugin::bar.bar');
|
||||
// ^ Valid, matches 'plugin::${string}.${string}'
|
||||
findOne('admin::foo');
|
||||
// ^ Valid, matches 'admin::${string}'
|
||||
|
||||
findOne('baz');
|
||||
// ^ Error, does not correspond to any content-type UID format
|
||||
```
|
||||
</TabItem>
|
||||
findOne('plugin::bar.bar');
|
||||
// ^ Valid, matches 'plugin::${string}.${string}'
|
||||
|
||||
findOne('baz');
|
||||
// ^ Error, does not correspond to any content-type UID format
|
||||
```
|
||||
</TabItem>
|
||||
</Tabs>
|
||||
|
||||
<!-- prettier-ignore-end -->
|
||||
|
Loading…
x
Reference in New Issue
Block a user