Bläddra i källkod

feat(core): Enable defining custom states in a type-safe manner (#1678)

Alexander Shitikov 3 år sedan
förälder
incheckning
4e2b4adf6e

+ 18 - 0
docs/content/developer-guide/customizing-the-order-process/index.md

@@ -49,6 +49,7 @@ export const customerValidationProcess: CustomOrderProcess<'ValidatingCustomer'>
   },
 };
 ```
+
 This object means:
 
 * the `AddingItems` state may _only_ transition to the `ValidatingCustomer` state (`mergeStrategy: 'replace'` tells Vendure to discard any existing transition targets and replace with this one). 
@@ -122,6 +123,23 @@ const customerValidationProcess: CustomOrderProcess<'ValidatingCustomer'> = {
 
 ```
 
+## TypeScript Typings
+
+To make your custom states compatible with standard services you should declare your new states in the following way:
+
+```TypeScript
+// types.ts
+import { CustomOrderStates } from '@vendure/core';
+
+declare module '@vendure/core' {
+  interface CustomOrderStates {
+    ValidatingCustomer: never;
+  }
+}
+```
+
+This technique uses advanced TypeScript features - [declaration merging](https://www.typescriptlang.org/docs/handbook/declaration-merging.html#merging-interfaces) and  [ambient modules](https://www.typescriptlang.org/docs/handbook/modules.html#ambient-modules).
+
 ## Controlling custom states in the Admin UI
 
 If you have defined custom order states, the Admin UI will allow you to manually transition an 

+ 12 - 0
docs/content/developer-guide/payment-integrations/index.md

@@ -151,6 +151,18 @@ If you need to support an entirely different payment flow than the above, it is
 Here's an example which adds a new "Validating" state to the Payment state machine, and combines it with a [CustomOrderProcess]({{< relref "custom-order-process" >}}), [PaymentMethodHandler]({{< relref "payment-method-handler" >}}) and [OrderPlacedStrategy]({{< relref "order-placed-strategy" >}}).
 
 ```TypeScript
+// types.ts
+import { CustomOrderStates } from '@vendure/core';
+
+/**
+ * Declare your custom state in special interface to make it type-safe
+ */
+declare module '@vendure/core' {
+  interface CustomPaymentStates {
+    Validating: never;
+  }
+}
+
 /**
  * Define a new "Validating" Payment state, and set up the
  * permitted transitions to/from it.

+ 2 - 1
packages/core/src/config/fulfillment/custom-fulfillment-process.ts

@@ -6,6 +6,7 @@ import {
 } from '../../common/finite-state-machine/types';
 import { InjectableStrategy } from '../../common/types/injectable-strategy';
 import {
+    CustomFulfillmentStates,
     FulfillmentState,
     FulfillmentTransitionData,
 } from '../../service/helpers/fulfillment-state-machine/fulfillment-state';
@@ -18,7 +19,7 @@ import {
  *
  * @docsCategory fulfillment
  */
-export interface CustomFulfillmentProcess<State extends string> extends InjectableStrategy {
+export interface CustomFulfillmentProcess<State extends keyof CustomFulfillmentStates | string> extends InjectableStrategy {
     transitions?: Transitions<State, State | FulfillmentState> &
         Partial<Transitions<FulfillmentState | State>>;
     onTransitionStart?: OnTransitionStartFn<State | FulfillmentState, FulfillmentTransitionData>;

+ 2 - 2
packages/core/src/config/order/custom-order-process.ts

@@ -6,7 +6,7 @@ import {
     Transitions,
 } from '../../common/finite-state-machine/types';
 import { InjectableStrategy } from '../../common/types/injectable-strategy';
-import { OrderState, OrderTransitionData } from '../../service/helpers/order-state-machine/order-state';
+import { CustomOrderStates, OrderState, OrderTransitionData } from '../../service/helpers/order-state-machine/order-state';
 
 /**
  * @description
@@ -16,7 +16,7 @@ import { OrderState, OrderTransitionData } from '../../service/helpers/order-sta
  *
  * @docsCategory orders
  */
-export interface CustomOrderProcess<State extends string> extends InjectableStrategy {
+export interface CustomOrderProcess<State extends keyof CustomOrderStates | string> extends InjectableStrategy {
     transitions?: Transitions<State, State | OrderState> & Partial<Transitions<OrderState | State>>;
     onTransitionStart?: OnTransitionStartFn<State | OrderState, OrderTransitionData>;
     onTransitionEnd?: OnTransitionEndFn<State | OrderState, OrderTransitionData>;

+ 2 - 1
packages/core/src/config/payment/custom-payment-process.ts

@@ -6,6 +6,7 @@ import {
 } from '../../common/finite-state-machine/types';
 import { InjectableStrategy } from '../../common/types/injectable-strategy';
 import {
+    CustomPaymentStates,
     PaymentState,
     PaymentTransitionData,
 } from '../../service/helpers/payment-state-machine/payment-state';
@@ -18,7 +19,7 @@ import {
  *
  * @docsCategory fulfillment
  */
-export interface CustomPaymentProcess<State extends string> extends InjectableStrategy {
+export interface CustomPaymentProcess<State extends keyof CustomPaymentStates | string> extends InjectableStrategy {
     transitions?: Transitions<State, State | PaymentState> & Partial<Transitions<PaymentState | State>>;
     onTransitionStart?: OnTransitionStartFn<State | PaymentState, PaymentTransitionData>;
     onTransitionEnd?: OnTransitionEndFn<State | PaymentState, PaymentTransitionData>;

+ 9 - 1
packages/core/src/service/helpers/fulfillment-state-machine/fulfillment-state.ts

@@ -3,13 +3,21 @@ import { Transitions } from '../../../common/finite-state-machine/types';
 import { Fulfillment } from '../../../entity/fulfillment/fulfillment.entity';
 import { Order } from '../../../entity/order/order.entity';
 
+/**
+ * @description
+ * An interface to extend standard {@link FulfillmentState}.
+ * 
+ * @docsCategory fulfillment
+ */
+export interface CustomFulfillmentStates {}
+
 /**
  * @description
  * These are the default states of the fulfillment process.
  *
  * @docsCategory fulfillment
  */
-export type FulfillmentState = 'Created' | 'Pending' | 'Shipped' | 'Delivered' | 'Cancelled';
+export type FulfillmentState = 'Created' | 'Pending' | 'Shipped' | 'Delivered' | 'Cancelled' | keyof CustomFulfillmentStates;
 
 export const fulfillmentStateTransitions: Transitions<FulfillmentState> = {
     Created: {

+ 10 - 1
packages/core/src/service/helpers/order-state-machine/order-state.ts

@@ -2,6 +2,14 @@ import { RequestContext } from '../../../api/common/request-context';
 import { Transitions } from '../../../common/finite-state-machine/types';
 import { Order } from '../../../entity/order/order.entity';
 
+/**
+ * @description
+ * An interface to extend standard {@link OrderState}.
+ * 
+ * @docsCategory orders
+ */
+ export interface CustomOrderStates {}
+
 /**
  * @description
  * These are the default states of the Order process. They can be augmented and
@@ -21,7 +29,8 @@ export type OrderState =
     | 'Delivered'
     | 'Modifying'
     | 'ArrangingAdditionalPayment'
-    | 'Cancelled';
+    | 'Cancelled'
+    | keyof CustomOrderStates;
 
 export const orderStateTransitions: Transitions<OrderState> = {
     Created: {

+ 9 - 1
packages/core/src/service/helpers/payment-state-machine/payment-state.ts

@@ -3,13 +3,21 @@ import { Transitions } from '../../../common/finite-state-machine/types';
 import { Order } from '../../../entity/order/order.entity';
 import { Payment } from '../../../entity/payment/payment.entity';
 
+/**
+ * @description
+ * An interface to extend standard {@link PaymentState}.
+ * 
+ * @docsCategory payment
+ */
+ export interface CustomPaymentStates {}
+
 /**
  * @description
  * These are the default states of the payment process.
  *
  * @docsCategory payment
  */
-export type PaymentState = 'Created' | 'Authorized' | 'Settled' | 'Declined' | 'Error' | 'Cancelled';
+export type PaymentState = 'Created' | 'Authorized' | 'Settled' | 'Declined' | 'Error' | 'Cancelled' | keyof CustomPaymentStates;
 
 export const paymentStateTransitions: Transitions<PaymentState> = {
     Created: {