Skip to content

Commit

Permalink
docs: update code formatting and minor text adjustments in type syste…
Browse files Browse the repository at this point in the history
…m documentation (#20186)
  • Loading branch information
Convly committed Apr 23, 2024
1 parent bdaafbb commit 01bf5cf
Show file tree
Hide file tree
Showing 3 changed files with 71 additions and 57 deletions.
19 changes: 11 additions & 8 deletions docs/docs/guides/05-type-system/02-concepts/01-schema.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -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>
Expand All @@ -89,29 +89,31 @@ 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.

:::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';

Expand All @@ -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>
18 changes: 10 additions & 8 deletions docs/docs/guides/05-type-system/02-concepts/02-uid.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand All @@ -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))
Expand All @@ -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 |

Expand All @@ -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 |
Expand Down Expand Up @@ -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: |
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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>`)

Expand Down
91 changes: 50 additions & 41 deletions docs/docs/guides/05-type-system/02-concepts/03-public-registry.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down Expand Up @@ -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

Expand All @@ -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,
Expand All @@ -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];
```
Expand All @@ -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.

Expand All @@ -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
Expand All @@ -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>
:::
Expand All @@ -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.

Expand All @@ -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>

Expand Down Expand Up @@ -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"
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) {
// ...
<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('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 -->

0 comments on commit 01bf5cf

Please sign in to comment.