docs: document InferTypeOf (#9321)

- Add documentation on how to use InferTypeOf
- Use InferTypeOf in recipes and examples
This commit is contained in:
Shahed Nasser authored and GitHub committed 2024-09-26 13:42:29 +00:00
1 parent c5bf22f3f4
commit b3a204e974
12 files changed
+170 -112

No files matched your search

@@ -0,0 +1,42 @@
export const metadata = {
title: `${pageNumber} Infer Type of Data Model`,
}
# {metadata.title}
In this chapter, you'll learn how to infer the type of a data model.
## How to Infer Type of Data Model?
Consider you have a `MyCustom` data model. You can't reference this data model in a type, such as a workflow input or service method output types, since it's a variable.
Instead, Medusa provides an `InferTypeOf` utility imported from `@medusajs/types` that transforms your data model to a type.
For example:
```ts
import { InferTypeOf } from "@medusajs/types"
import { MyCustom } from "../models/my-custom" // relative path to the model
export type MyCustom = InferTypeOf<typeof MyCustom>
```
The `InferTypeOf` utility accepts as a type argument the type of the data model.
Since the `MyCustom` data model is a variable, use the `typeof` operator to pass the data model as a type argument to `InferTypeOf`.
You can now use the `MyCustom` type to reference a data model in other types, such as in workflow inputs or service method outputs:
```ts title="Example Service"
// other imports...
import { InferTypeOf } from "@medusajs/types"
import { MyCustom } from "../models/my-custom"
type MyCustom = InferTypeOf<typeof MyCustom>
class HelloModuleService extends MedusaService({ MyCustom }) {
async doSomething(): Promise<MyCustom> {
// ...
}
}
```
@@ -21,8 +21,8 @@ It’s registered in the Medusa container under the `ContainerRegistrationKeys.R
For example, consider the following step: For example, consider the following step:
export const stepHighlights = [ export const stepHighlights = [
["14", "resolve", "Resolve the remote link."], ["19", "resolve", "Resolve the remote link."],
["18", "create", "Create a link between two records."] ["23", "create", "Create a link between two records."]
] ]
```ts highlights={stepHighlights} collapsibleLines="1-10" expandButtonLabel="Show Imports" ```ts highlights={stepHighlights} collapsibleLines="1-10" expandButtonLabel="Show Imports"
@@ -36,9 +36,14 @@ import {
} from "@medusajs/utils" } from "@medusajs/utils"
import { BRAND_MODULE } from "../../modules/brand" import { BRAND_MODULE } from "../../modules/brand"
type LinkProductToBrandStepInput = {
productId: string
brandId: string
}
export const linkProductToBrandStep = createStep( export const linkProductToBrandStep = createStep(
"link-product-to-brand", "link-product-to-brand",
async ({ productId, brandId }, { container }) => { async ({ productId, brandId }: LinkProductToBrandStepInput, { container }) => {
const remoteLink = container.resolve( const remoteLink = container.resolve(
ContainerRegistrationKeys.REMOTE_LINK ContainerRegistrationKeys.REMOTE_LINK
) )
@@ -66,20 +66,22 @@ The step returns the retrieved brands.
Next, create the step that creates new brands in Medusa in the file `src/workflows/sync-brands-from-system/steps/create-brands.ts`: Next, create the step that creates new brands in Medusa in the file `src/workflows/sync-brands-from-system/steps/create-brands.ts`:
export const createBrandsHighlights = [ export const createBrandsHighlights = [
["19", "createBrands", "Create the brands in Medusa"], ["21", "createBrands", "Create the brands in Medusa"],
["28", "deleteBrands", "Delete the brands from Medusa"] ["30", "deleteBrands", "Delete the brands from Medusa"]
] ]
```ts title="src/workflows/sync-brands-from-system/steps/create-brands.ts" highlights={createBrandsHighlights} collapsibleLines="1-7" expandButtonLabel="Show Imports" ```ts title="src/workflows/sync-brands-from-system/steps/create-brands.ts" highlights={createBrandsHighlights} collapsibleLines="1-9" expandButtonLabel="Show Imports"
import { import {
createStep, createStep,
StepResponse, StepResponse,
} from "@medusajs/workflows-sdk" } from "@medusajs/workflows-sdk"
import { InferTypeOf } from "@medusajs/types"
import BrandModuleService from "../../../modules/brand/service" import BrandModuleService from "../../../modules/brand/service"
import { BRAND_MODULE } from "../../../modules/brand" import { BRAND_MODULE } from "../../../modules/brand"
import { Brand } from "../../../modules/brand/models/brand"
type CreateBrandsInput = { type CreateBrandsInput = {
brands: Record<string, string>[] brands: InferTypeOf<typeof Brand>[]
} }
export const createBrandsStep = createStep( export const createBrandsStep = createStep(
@@ -105,6 +107,12 @@ export const createBrandsStep = createStep(
This step receives the brands to create as input. This step receives the brands to create as input.
<Note title="Tip">
Since a data model is a variable, use the `InferTypeOf` utility imported from `@medusajs/types` to infer its type.
</Note>
In the step, you resolve the Brand Module's main service and uses its `createBrands` method to create the brands. In the step, you resolve the Brand Module's main service and uses its `createBrands` method to create the brands.
You return the created brands and pass their IDs to the compensation function, which deletes the brands if an error occurs. You return the created brands and pass their IDs to the compensation function, which deletes the brands if an error occurs.
@@ -114,21 +122,23 @@ You return the created brands and pass their IDs to the compensation function, w
To create the step that updates existing brands in Medusa, create the file `src/workflows/sync-brands-from-system/steps/update-brands.ts` with the following content: To create the step that updates existing brands in Medusa, create the file `src/workflows/sync-brands-from-system/steps/update-brands.ts` with the following content:
export const updateBrandsHighlights = [ export const updateBrandsHighlights = [
["19", "prevUpdatedBrands", "Retrieve the data of the brands before the update."], ["21", "prevUpdatedBrands", "Retrieve the data of the brands before the update."],
["23", "updateBrands", "Update the brands in Medusa."], ["25", "updateBrands", "Update the brands in Medusa."],
["32", "updateBrands", "Revert the update by reverting the brands' to before the update."] ["34", "updateBrands", "Revert the update by reverting the brands' to before the update."]
] ]
```ts title="src/workflows/sync-brands-from-system/steps/update-brands.ts" highlights={updateBrandsHighlights} collapsibleLines="1-7" expandButtonLabel="Show Imports" ```ts title="src/workflows/sync-brands-from-system/steps/update-brands.ts" highlights={updateBrandsHighlights} collapsibleLines="1-9" expandButtonLabel="Show Imports"
import { import {
createStep, createStep,
StepResponse, StepResponse,
} from "@medusajs/workflows-sdk" } from "@medusajs/workflows-sdk"
import { InferTypeOf } from "@medusajs/types"
import BrandModuleService from "../../../modules/brand/service" import BrandModuleService from "../../../modules/brand/service"
import { BRAND_MODULE } from "../../../modules/brand" import { BRAND_MODULE } from "../../../modules/brand"
import { Brand } from "../../../modules/brand/models/brand"
type UpdateBrandsInput = { type UpdateBrandsInput = {
brands: Record<string, string>[] brands: InferTypeOf<typeof Brand>[]
} }
export const updateBrandsStep = createStep( export const updateBrandsStep = createStep(
@@ -172,9 +182,11 @@ import {
WorkflowResponse, WorkflowResponse,
transform, transform,
} from "@medusajs/workflows-sdk" } from "@medusajs/workflows-sdk"
import { InferTypeOf } from "@medusajs/types"
import { retrieveBrandsFromSystemStep } from "./steps/retrieve-brands-from-system" import { retrieveBrandsFromSystemStep } from "./steps/retrieve-brands-from-system"
import { createBrandsStep } from "./steps/create-brands" import { createBrandsStep } from "./steps/create-brands"
import { updateBrandsStep } from "./steps/update-brands" import { updateBrandsStep } from "./steps/update-brands"
import { Brand } from "../../modules/brand/models/brand"
export const syncBrandsFromSystemWorkflow = createWorkflow( export const syncBrandsFromSystemWorkflow = createWorkflow(
"sync-brands-from-system", "sync-brands-from-system",
@@ -204,8 +216,8 @@ const { toCreate, toUpdate } = transform(
brands, brands,
}, },
(data) => { (data) => {
const toCreate: Record<string, string>[] = [] const toCreate: InferTypeOf<typeof Brand>[] = []
const toUpdate: Record<string, string>[] = [] const toUpdate: InferTypeOf<typeof Brand>[] = []
data.brands.forEach((brand) => { data.brands.forEach((brand) => {
if (brand.external_id) { if (brand.external_id) {
@@ -80,13 +80,17 @@ If the service integrating the third-party system was a main service, it receive
Next, add the following methods to simulate sending requests to the third-party system: Next, add the following methods to simulate sending requests to the third-party system:
export const methodsHighlights = [ export const methodsHighlights = [
["6", "sendRequest", "Since the third-party system isn't real, this method only logs a message."], ["10", "sendRequest", "Since the third-party system isn't real, this method only logs a message."],
["15", "createBrand", "A method that creates a brand in the third-party system."], ["19", "createBrand", "A method that creates a brand in the third-party system."],
["19", "deleteBrand", "A method that deletes a brand in the third-party system."], ["23", "deleteBrand", "A method that deletes a brand in the third-party system."],
["23", "retrieveBrands", "A method that retrieves a brand from a third-party system."] ["27", "retrieveBrands", "A method that retrieves a brand from a third-party system."]
] ]
```ts title="src/modules/brand/services/client.ts" highlights={methodsHighlights} ```ts title="src/modules/brand/services/client.ts" highlights={methodsHighlights}
// other imports...
import { InferTypeOf } from "@medusajs/types"
import { Brand } from "../models/brand"
export class BrandClient { export class BrandClient {
// ... // ...
@@ -101,7 +105,7 @@ export class BrandClient {
}`) }`)
} }
async createBrand(brand: Record<string, any>) { async createBrand(brand: InferTypeOf<typeof Brand>) {
await this.sendRequest("/brands", "POST", brand) await this.sendRequest("/brands", "POST", brand)
} }
@@ -121,7 +125,7 @@ The `sendRequest` method is a dummy method to simulate sending a request to a th
You also add three methods that use the `sendRequest` method: You also add three methods that use the `sendRequest` method:
- `createBrand` that creates a brand in the third-party system. - `createBrand` that creates a brand in the third-party system. To reference a brand's type, you use the `InferTypeOf` utility imported from `@medusajs/types`. This transforms a data model, which is a variable, to its equivalent type.
- `deleteBrand` that deletes the brand in the third-party system. - `deleteBrand` that deletes the brand in the third-party system.
- `retrieveBrands` to retrieve a brand from the third-party system. - `retrieveBrands` to retrieve a brand from the third-party system.
+6 -5
View File
@@ -87,7 +87,7 @@ export const generatedEditDates = {
"app/customization/custom-features/api-route/page.mdx": "2024-09-12T12:42:34.201Z", "app/customization/custom-features/api-route/page.mdx": "2024-09-12T12:42:34.201Z",
"app/customization/custom-features/module/page.mdx": "2024-09-12T12:39:37.928Z", "app/customization/custom-features/module/page.mdx": "2024-09-12T12:39:37.928Z",
"app/customization/custom-features/workflow/page.mdx": "2024-09-12T12:40:39.582Z", "app/customization/custom-features/workflow/page.mdx": "2024-09-12T12:40:39.582Z",
"app/customization/extend-models/create-links/page.mdx": "2024-09-12T12:42:55.602Z", "app/customization/extend-models/create-links/page.mdx": "2024-09-26T08:31:08.177Z",
"app/customization/extend-models/extend-create-product/page.mdx": "2024-09-12T12:43:57.702Z", "app/customization/extend-models/extend-create-product/page.mdx": "2024-09-12T12:43:57.702Z",
"app/customization/custom-features/page.mdx": "2024-09-12T11:18:13.271Z", "app/customization/custom-features/page.mdx": "2024-09-12T11:18:13.271Z",
"app/customization/customize-admin/page.mdx": "2024-09-12T12:25:29.853Z", "app/customization/customize-admin/page.mdx": "2024-09-12T12:25:29.853Z",
@@ -96,14 +96,15 @@ export const generatedEditDates = {
"app/customization/extend-models/define-link/page.mdx": "2024-09-12T12:38:53.230Z", "app/customization/extend-models/define-link/page.mdx": "2024-09-12T12:38:53.230Z",
"app/customization/extend-models/page.mdx": "2024-09-12T12:38:57.394Z", "app/customization/extend-models/page.mdx": "2024-09-12T12:38:57.394Z",
"app/customization/extend-models/query-linked-records/page.mdx": "2024-09-12T12:44:41.089Z", "app/customization/extend-models/query-linked-records/page.mdx": "2024-09-12T12:44:41.089Z",
"app/customization/integrate-systems/handle-event/page.mdx": "2024-09-12T12:39:07.978Z", "app/customization/integrate-systems/handle-event/page.mdx": "2024-09-26T08:34:57.278Z",
"app/customization/integrate-systems/page.mdx": "2024-09-12T12:33:29.827Z", "app/customization/integrate-systems/page.mdx": "2024-09-12T12:33:29.827Z",
"app/customization/integrate-systems/schedule-task/page.mdx": "2024-09-12T12:46:17.591Z", "app/customization/integrate-systems/schedule-task/page.mdx": "2024-09-26T08:40:26.509Z",
"app/customization/integrate-systems/service/page.mdx": "2024-09-12T12:39:12.831Z", "app/customization/integrate-systems/service/page.mdx": "2024-09-26T08:34:30.313Z",
"app/customization/next-steps/page.mdx": "2024-09-12T10:50:04.873Z", "app/customization/next-steps/page.mdx": "2024-09-12T10:50:04.873Z",
"app/customization/page.mdx": "2024-09-12T11:16:18.504Z", "app/customization/page.mdx": "2024-09-12T11:16:18.504Z",
"app/more-resources/cheatsheet/page.mdx": "2024-07-11T16:11:26.480Z", "app/more-resources/cheatsheet/page.mdx": "2024-07-11T16:11:26.480Z",
"app/more-resources/examples/page.mdx": "2024-09-19T10:30:30.398Z", "app/more-resources/examples/page.mdx": "2024-09-19T10:30:30.398Z",
"app/architecture/architectural-modules/page.mdx": "2024-09-23T12:51:04.520Z", "app/architecture/architectural-modules/page.mdx": "2024-09-23T12:51:04.520Z",
"app/architecture/overview/page.mdx": "2024-09-23T12:55:01.339Z" "app/architecture/overview/page.mdx": "2024-09-23T12:55:01.339Z",
"app/advanced-development/data-models/infer-type/page.mdx": "2024-09-26T08:28:13.041Z"
} }
+5
View File
@@ -310,6 +310,11 @@ export const sidebar = numberSidebarItems(
path: "/advanced-development/data-models", path: "/advanced-development/data-models",
title: "Data Models", title: "Data Models",
children: [ children: [
{
type: "link",
path: "/advanced-development/data-models/infer-type",
title: "Infer Type",
},
{ {
type: "link", type: "link",
path: "/advanced-development/data-models/property-types", path: "/advanced-development/data-models/property-types",
@@ -58,7 +58,7 @@ const { data: products } = await query.graph({
region_id: "region_123", region_id: "region_123",
currency_code: "usd", currency_code: "usd",
}), }),
} },
}, },
}) })
``` ```
@@ -1575,12 +1575,13 @@ You’ll only implement the `3.a` step of the workflow.
Create the file `src/workflows/create-digital-product-order/steps/create-digital-product-order.ts` with the following content: Create the file `src/workflows/create-digital-product-order/steps/create-digital-product-order.ts` with the following content:
export const createDpoHighlights = [ export const createDpoHighlights = [
["18", "InferTypeOf", "Infer the type of the `DigitalProduct` data model since it's a variable."],
["33", "createDigitalProductOrders", "Create the digital product order."], ["33", "createDigitalProductOrders", "Create the digital product order."],
["41", "digital_product_order", "Pass the created digital product order to the compensation function."], ["41", "digital_product_order", "Pass the created digital product order to the compensation function."],
["48", "deleteDigitalProductOrders", "Delete the digital product order if an error occurs in the workflow."] ["48", "deleteDigitalProductOrders", "Delete the digital product order if an error occurs in the workflow."]
] ]
```ts title="src/workflows/create-digital-product-order/steps/create-digital-product-order.ts" highlights={createDpoHighlights} collapsibleLines="1-15" expandMoreLabel="Show Imports" ```ts title="src/workflows/create-digital-product-order/steps/create-digital-product-order.ts" highlights={createDpoHighlights} collapsibleLines="1-14" expandMoreLabel="Show Imports"
import { import {
createStep, createStep,
StepResponse, StepResponse,
@@ -1588,18 +1589,17 @@ import {
import { import {
OrderLineItemDTO, OrderLineItemDTO,
ProductVariantDTO, ProductVariantDTO,
InferTypeOf,
} from "@medusajs/types" } from "@medusajs/types"
import { import { OrderStatus } from "../../../modules/digital-product/types"
DigitalProductData,
OrderStatus,
} from "../../../modules/digital-product/types"
import DigitalProductModuleService from "../../../modules/digital-product/service" import DigitalProductModuleService from "../../../modules/digital-product/service"
import { DIGITAL_PRODUCT_MODULE } from "../../../modules/digital-product" import { DIGITAL_PRODUCT_MODULE } from "../../../modules/digital-product"
import DigitalProduct from "../../../modules/digital-product/models/digital-product"
type StepInput = { type StepInput = {
items: (OrderLineItemDTO & { items: (OrderLineItemDTO & {
variant: ProductVariantDTO & { variant: ProductVariantDTO & {
digital_product: DigitalProductData digital_product: InferTypeOf<typeof DigitalProduct>
} }
})[] })[]
} }
@@ -1833,20 +1833,21 @@ So, you only need to implement the second step.
Before creating the step, add to `src/modules/digital-product/types/index.ts` the following: Before creating the step, add to `src/modules/digital-product/types/index.ts` the following:
```ts ```ts
import { OrderDTO } from "@medusajs/types" import { OrderDTO, InferTypeOf } from "@medusajs/types"
import DigitalProductOrder from "../models/digital-product-order"
// ... // ...
export type DigitalProductOrderData = { export type DigitalProductOrder =
id: string InferTypeOf<typeof DigitalProductOrder> & {
status: OrderStatus order?: OrderDTO
products?: DigitalProductData[] }
order?: OrderDTO
}
``` ```
This adds a type for a digital product order, which you'll use next. This adds a type for a digital product order, which you'll use next.
You use the `InferTypeOf` utility to infer the type of the `DigitalProductOrder` data model, and add to it the optional `order` property, which is the linked order.
### Create sendDigitalOrderNotificationStep ### Create sendDigitalOrderNotificationStep
To create the step, create the file `src/workflows/fulfill-digital-order/steps/send-digital-order-notification.ts` with the following content: To create the step, create the file `src/workflows/fulfill-digital-order/steps/send-digital-order-notification.ts` with the following content:
@@ -1854,23 +1855,23 @@ To create the step, create the file `src/workflows/fulfill-digital-order/steps/s
```ts title="src/workflows/fulfill-digital-order/steps/send-digital-order-notification.ts" collapsibleLines="1-11" expandMoreLabel="Show Imports" ```ts title="src/workflows/fulfill-digital-order/steps/send-digital-order-notification.ts" collapsibleLines="1-11" expandMoreLabel="Show Imports"
import { import {
createStep, createStep,
StepResponse StepResponse,
} from "@medusajs/workflows-sdk" } from "@medusajs/workflows-sdk"
import { import {
INotificationModuleService, INotificationModuleService,
IFileModuleService IFileModuleService,
} from "@medusajs/types" } from "@medusajs/types"
import { ModuleRegistrationName } from "@medusajs/utils" import { ModuleRegistrationName } from "@medusajs/utils"
import { DigitalProductOrderData, MediaType } from "../../../modules/digital-product/types" import { DigitalProductOrder, MediaType } from "../../../modules/digital-product/types"
type SendDigitalOrderNotificationStepInput = { type SendDigitalOrderNotificationStepInput = {
digital_product_order: DigitalProductOrderData digital_product_order: DigitalProductOrder
} }
export const sendDigitalOrderNotificationStep = createStep( export const sendDigitalOrderNotificationStep = createStep(
"send-digital-order-notification", "send-digital-order-notification",
async ({ async ({
digital_product_order: digitalProductOrder digital_product_order: digitalProductOrder,
}: SendDigitalOrderNotificationStepInput, }: SendDigitalOrderNotificationStepInput,
{ container }) => { { container }) => {
const notificationModuleService: INotificationModuleService = container const notificationModuleService: INotificationModuleService = container
@@ -1907,7 +1908,7 @@ const notificationData = await Promise.all(
return { return {
name: product.name, name: product.name,
medias medias,
} }
}) })
) )
@@ -1925,8 +1926,8 @@ const notification = await notificationModuleService.createNotifications({
template: "digital-order-template", template: "digital-order-template",
channel: "email", channel: "email",
data: { data: {
products: notificationData products: notificationData,
} },
}) })
return new StepResponse(notification) return new StepResponse(notification)
@@ -1946,10 +1947,10 @@ export const fulfillWorkflowHighlights = [
```ts title="src/workflows/fulfill-digital-order/index.ts" highlights={fulfillWorkflowHighlights} collapsibleLines="1-10" expandMoreLabel="Show Imports" ```ts title="src/workflows/fulfill-digital-order/index.ts" highlights={fulfillWorkflowHighlights} collapsibleLines="1-10" expandMoreLabel="Show Imports"
import { import {
createWorkflow, createWorkflow,
WorkflowResponse WorkflowResponse,
} from "@medusajs/workflows-sdk" } from "@medusajs/workflows-sdk"
import { import {
useRemoteQueryStep useRemoteQueryStep,
} from "@medusajs/core-flows" } from "@medusajs/core-flows"
import { sendDigitalOrderNotificationStep } from "./steps/send-digital-order-notification" import { sendDigitalOrderNotificationStep } from "./steps/send-digital-order-notification"
@@ -1966,7 +1967,7 @@ export const fulfillDigitalOrderWorkflow = createWorkflow(
"*", "*",
"products.*", "products.*",
"products.medias.*", "products.medias.*",
"order.*" "order.*",
], ],
variables: { variables: {
filters: { filters: {
@@ -1974,11 +1975,11 @@ export const fulfillDigitalOrderWorkflow = createWorkflow(
}, },
}, },
list: false, list: false,
throw_if_key_not_found: true throw_if_key_not_found: true,
}) })
sendDigitalOrderNotificationStep({ sendDigitalOrderNotificationStep({
digital_product_order: digitalProductOrder digital_product_order: digitalProductOrder,
}) })
return new WorkflowResponse( return new WorkflowResponse(
@@ -2021,7 +2022,7 @@ module.exports = defineConfig({
], ],
}, },
}, },
} },
}) })
``` ```
@@ -2040,7 +2041,7 @@ import type {
SubscriberConfig, SubscriberConfig,
} from "@medusajs/medusa" } from "@medusajs/medusa"
import { import {
fulfillDigitalOrderWorkflow fulfillDigitalOrderWorkflow,
} from "../workflows/fulfill-digital-order" } from "../workflows/fulfill-digital-order"
async function digitalProductOrderCreatedHandler({ async function digitalProductOrderCreatedHandler({
@@ -2049,8 +2050,8 @@ async function digitalProductOrderCreatedHandler({
}: SubscriberArgs<{ id: string }>) { }: SubscriberArgs<{ id: string }>) {
await fulfillDigitalOrderWorkflow(container).run({ await fulfillDigitalOrderWorkflow(container).run({
input: { input: {
id: data.id id: data.id,
} },
}) })
} }
@@ -435,17 +435,13 @@ Before implementing the functionalities, you’ll create type files in the Resta
Create the file `src/modules/restaurant/types/index.ts` with the following content: Create the file `src/modules/restaurant/types/index.ts` with the following content:
```ts title="src/modules/restaurant/types/index.ts" ```ts title="src/modules/restaurant/types/index.ts"
import { InferTypeOf } from "@medusajs/types"
import RestaurantModuleService from "../service" import RestaurantModuleService from "../service"
import { Restaurant } from "../models/restaurant"
export interface CreateRestaurant { export type CreateRestaurant = Omit<
name: string; InferTypeOf<typeof Restaurant>, "id" | "admins"
handle: string; >
address: string;
phone: string;
email: string;
image_url?: string;
is_open?: boolean;
}
declare module "@medusajs/types" { declare module "@medusajs/types" {
export interface ModuleImplementations { export interface ModuleImplementations {
@@ -456,6 +452,12 @@ declare module "@medusajs/types" {
This adds a type used for inputs in creating a restaurant. It also adds a type for `restaurantModuleService` in `ModuleImplementations` so that when you resolve it from the Medusa container, it has the correct typing. This adds a type used for inputs in creating a restaurant. It also adds a type for `restaurantModuleService` in `ModuleImplementations` so that when you resolve it from the Medusa container, it has the correct typing.
<Note title="Tip">
Since the `Restaurant` data model is a variable, use the `InferTypeOf` utility imported from `@medusajs/types` to infer its type.
</Note>
### Create Workflow ### Create Workflow
To implement the functionality of creating a restaurant, create a workflow and execute it in the API route. To implement the functionality of creating a restaurant, create a workflow and execute it in the API route.
@@ -630,7 +632,7 @@ In the file `src/api/restaurants/route.ts` add the following API route:
import { MedusaRequest, MedusaResponse } from "@medusajs/medusa" import { MedusaRequest, MedusaResponse } from "@medusajs/medusa"
import { import {
ContainerRegistrationKeys, ContainerRegistrationKeys,
QueryContext QueryContext,
} from "@medusajs/utils" } from "@medusajs/utils"
// ... // ...
@@ -662,7 +664,7 @@ export async function GET(req: MedusaRequest, res: MedusaResponse) {
variants: { variants: {
calculated_price: QueryContext({ calculated_price: QueryContext({
currency_code, currency_code,
}) }),
}, },
}, },
}, },
@@ -2259,40 +2261,26 @@ Before implementing the necessary functionalities, add the following types to `s
```ts title="src/modules/delivery/types/index.ts" ```ts title="src/modules/delivery/types/index.ts"
// other imports... // other imports...
import { import { InferTypeOf } from "@medusajs/types"
CartLineItemDTO, import { Delivery } from "../models/delivery"
OrderLineItemDTO,
CartDTO,
OrderDTO,
} from "@medusajs/types"
// ... // ...
export interface Delivery { export type Delivery = InferTypeOf<typeof Delivery>
id: string;
transaction_id: string;
driver_id?: string;
delivered_at?: Date;
delivery_status: DeliveryStatus;
created_at: Date;
updated_at: Date;
eta?: Date;
items: DeliveryItem[];
cart?: CartDTO;
order?: OrderDTO;
}
export type DeliveryItem = (CartLineItemDTO | OrderLineItemDTO) & { export type UpdateDelivery = Partial<Delivery> & {
quantity: number;
}
export interface UpdateDelivery extends Partial<Delivery> {
id: string; id: string;
} }
``` ```
These types are useful in the upcoming implementation steps. These types are useful in the upcoming implementation steps.
<Note title="Tip">
Since the `Delivery` data model is a variable, use the `InferTypeOf` utility imported from `@medusajs/types` to infer its type.
</Note>
### Create Workflow ### Create Workflow
As the API route should update the delivery’s status, you’ll create a new workflow to implement that functionality. As the API route should update the delivery’s status, you’ll create a new workflow to implement that functionality.
@@ -862,11 +862,11 @@ This step groups the items by the vendor associated with the product into an obj
Next, create the fourth step in the file `src/workflows/marketplace/create-vendor-orders/steps/create-vendor-orders.ts`: Next, create the fourth step in the file `src/workflows/marketplace/create-vendor-orders/steps/create-vendor-orders.ts`:
export const vendorOrder1Highlights = [ export const vendorOrder1Highlights = [
["41", "linkDefs", "An array of links to be created."], ["42", "linkDefs", "An array of links to be created."],
["58", "created_orders", "Pass the created orders to the compensation function."] ["59", "created_orders", "Pass the created orders to the compensation function."]
] ]
```ts title="src/workflows/marketplace/create-vendor-orders/steps/create-vendor-orders.ts" highlights={vendorOrder1Highlights} collapsibleLines="1-18" expandMoreLabel="Show Imports" ```ts title="src/workflows/marketplace/create-vendor-orders/steps/create-vendor-orders.ts" highlights={vendorOrder1Highlights} collapsibleLines="1-19" expandMoreLabel="Show Imports"
import { import {
createStep, createStep,
StepResponse, StepResponse,
@@ -874,7 +874,8 @@ import {
import { import {
CartLineItemDTO, CartLineItemDTO,
OrderDTO, OrderDTO,
LinkDefinition LinkDefinition,
InferTypeOf,
} from "@medusajs/types" } from "@medusajs/types"
import { Modules } from "@medusajs/utils" import { Modules } from "@medusajs/utils"
import { import {
@@ -883,10 +884,10 @@ import {
} from "@medusajs/core-flows" } from "@medusajs/core-flows"
import MarketplaceModuleService from "../../../../modules/marketplace/service" import MarketplaceModuleService from "../../../../modules/marketplace/service"
import { MARKETPLACE_MODULE } from "../../../../modules/marketplace" import { MARKETPLACE_MODULE } from "../../../../modules/marketplace"
import { VendorData } from "../../../../modules/marketplace/types" import Vendor from "../../../../modules/marketplace/models/vendor"
export type VendorOrder = (OrderDTO & { export type VendorOrder = (OrderDTO & {
vendor: VendorData vendor: InferTypeOf<typeof Vendor>
}) })
type StepInput = { type StepInput = {
@@ -363,6 +363,9 @@ The `getExpirationDate` method accepts a subscription’s date, interval, and pe
Before overriding the `createSubscriptions` method, add the following types to `src/modules/subscription/types/index.ts`: Before overriding the `createSubscriptions` method, add the following types to `src/modules/subscription/types/index.ts`:
```ts title="src/modules/subscription/types/index.ts" ```ts title="src/modules/subscription/types/index.ts"
import { InferTypeOf } from "@medusajs/types"
import Subscription from "../models/subscription"
// ... // ...
export type CreateSubscriptionData = { export type CreateSubscriptionData = {
@@ -373,19 +376,15 @@ export type CreateSubscriptionData = {
metadata?: Record<string, unknown> metadata?: Record<string, unknown>
} }
export type SubscriptionData = { export type SubscriptionData = InferTypeOf<typeof Subscription>
id: string
status: SubscriptionStatus
interval: SubscriptionInterval
subscription_date: Date
last_order_date: Date
next_order_date: Date | null
expiration_date: Date
metadata: Record<string, unknown> | null
}
``` ```
<Note title="Tip">
Since the `Subscription` data model is a variable, use the `InferTypeOf` utility imported from `@medusajs/types` to infer its type.
</Note>
Then, in `src/modules/subscription/service.ts`, add the following to override the `createSubscriptions` method: Then, in `src/modules/subscription/service.ts`, add the following to override the `createSubscriptions` method:
```ts title="src/modules/subscription/service.ts" ```ts title="src/modules/subscription/service.ts"
+4 -4
View File
@@ -141,18 +141,18 @@ export const generatedEditDates = {
"app/nextjs-starter/page.mdx": "2024-07-01T10:21:19+03:00", "app/nextjs-starter/page.mdx": "2024-07-01T10:21:19+03:00",
"app/recipes/b2b/page.mdx": "2024-08-29T09:23:12.736Z", "app/recipes/b2b/page.mdx": "2024-08-29T09:23:12.736Z",
"app/recipes/commerce-automation/page.mdx": "2024-08-05T07:24:27+00:00", "app/recipes/commerce-automation/page.mdx": "2024-08-05T07:24:27+00:00",
"app/recipes/digital-products/examples/standard/page.mdx": "2024-09-17T14:30:02.190Z", "app/recipes/digital-products/examples/standard/page.mdx": "2024-09-26T09:00:12.671Z",
"app/recipes/digital-products/page.mdx": "2024-08-02T13:02:06+00:00", "app/recipes/digital-products/page.mdx": "2024-08-02T13:02:06+00:00",
"app/recipes/ecommerce/page.mdx": "2024-06-09T15:18:43+02:00", "app/recipes/ecommerce/page.mdx": "2024-06-09T15:18:43+02:00",
"app/recipes/integrate-ecommerce-stack/page.mdx": "2024-08-05T07:24:27+00:00", "app/recipes/integrate-ecommerce-stack/page.mdx": "2024-08-05T07:24:27+00:00",
"app/recipes/marketplace/examples/vendors/page.mdx": "2024-09-02T14:06:37.189Z", "app/recipes/marketplace/examples/vendors/page.mdx": "2024-09-26T09:06:11.833Z",
"app/recipes/marketplace/page.mdx": "2024-07-11T15:56:41+00:00", "app/recipes/marketplace/page.mdx": "2024-07-11T15:56:41+00:00",
"app/recipes/multi-region-store/page.mdx": "2024-07-01T10:21:19+03:00", "app/recipes/multi-region-store/page.mdx": "2024-07-01T10:21:19+03:00",
"app/recipes/omnichannel/page.mdx": "2024-06-09T15:18:43+02:00", "app/recipes/omnichannel/page.mdx": "2024-06-09T15:18:43+02:00",
"app/recipes/oms/page.mdx": "2024-07-01T10:21:19+03:00", "app/recipes/oms/page.mdx": "2024-07-01T10:21:19+03:00",
"app/recipes/personalized-products/page.mdx": "2024-09-11T10:53:03.936Z", "app/recipes/personalized-products/page.mdx": "2024-09-11T10:53:03.936Z",
"app/recipes/pos/page.mdx": "2024-07-04T17:26:03+03:00", "app/recipes/pos/page.mdx": "2024-07-04T17:26:03+03:00",
"app/recipes/subscriptions/examples/standard/page.mdx": "2024-09-11T10:16:35.673Z", "app/recipes/subscriptions/examples/standard/page.mdx": "2024-09-26T10:19:57.044Z",
"app/recipes/subscriptions/page.mdx": "2024-08-02T12:40:26+03:00", "app/recipes/subscriptions/page.mdx": "2024-08-02T12:40:26+03:00",
"app/recipes/page.mdx": "2024-07-11T15:56:41+00:00", "app/recipes/page.mdx": "2024-07-11T15:56:41+00:00",
"app/service-factory-reference/methods/create/page.mdx": "2024-07-31T17:01:33+03:00", "app/service-factory-reference/methods/create/page.mdx": "2024-07-31T17:01:33+03:00",
@@ -643,7 +643,7 @@ export const generatedEditDates = {
"app/medusa-cli/commands/start/page.mdx": "2024-08-28T10:44:19.952Z", "app/medusa-cli/commands/start/page.mdx": "2024-08-28T10:44:19.952Z",
"app/medusa-cli/commands/telemtry/page.mdx": "2024-08-28T11:25:08.553Z", "app/medusa-cli/commands/telemtry/page.mdx": "2024-08-28T11:25:08.553Z",
"app/medusa-cli/commands/user/page.mdx": "2024-08-28T10:44:52.489Z", "app/medusa-cli/commands/user/page.mdx": "2024-08-28T10:44:52.489Z",
"app/recipes/marketplace/examples/restaurant-delivery/page.mdx": "2024-09-11T13:29:33.305Z", "app/recipes/marketplace/examples/restaurant-delivery/page.mdx": "2024-09-26T10:12:17.661Z",
"references/types/HttpTypes/interfaces/types.HttpTypes.AdminCreateCustomerGroup/page.mdx": "2024-08-30T00:11:02.074Z", "references/types/HttpTypes/interfaces/types.HttpTypes.AdminCreateCustomerGroup/page.mdx": "2024-08-30T00:11:02.074Z",
"references/types/HttpTypes/interfaces/types.HttpTypes.AdminCreateReservation/page.mdx": "2024-08-30T00:11:02.342Z", "references/types/HttpTypes/interfaces/types.HttpTypes.AdminCreateReservation/page.mdx": "2024-08-30T00:11:02.342Z",
"references/types/HttpTypes/interfaces/types.HttpTypes.AdminCustomerGroup/page.mdx": "2024-08-30T00:11:02.070Z", "references/types/HttpTypes/interfaces/types.HttpTypes.AdminCustomerGroup/page.mdx": "2024-08-30T00:11:02.070Z",