# State

The workflow state keeps track of the state of the workflow as it progresses. The state is stored in the configured [persistence](https://bus.node-ts.com/guide/persistence), and can be used to map incoming messages to [handlers](https://bus.node-ts.com/guide/workflows/handling).&#x20;

### Defining the state

A workflow state is created by extending **WorkflowState.** The `$name` property should be unique among all of your workflows.&#x20;

```typescript
import { WorkflowState } from '@node-ts/bus-core'

export class FulfilmentWorkflowState extends WorkflowState {
  static NAME = 'FulfilmentWorkflowState'
  $name = FulfilmentWorkflowState.NAME
  
  // Set of user-defined state properties
  itemId: string
  customerId: string
  status: 'posting-item' | 'sending-receipt' | 'complete'
}
```

### Accessing the state

The state is available as the second parameter to all handlers of a workflow. For example:

```typescript
import { Workflow } from '@node-ts/bus-core'

export class FulfilmentWorkflow extends Workflow<FulfilmentWorkflowState> {
  configureWorkflow (
    mapper: WorkflowMapper<FulfilmentWorkflowState, FulfilmentWorkflow>
  ): void {
    mapper
      .withState(FulfilmentWorkflowState)
      // ...
      .when(ItemShipped, 'emailReceipt')
  }
  
  // Workflow state is passed in as the second parameter to a workflow handler
  async emailReceipt (_: ItemShipped, state: FulfilmentWorkflowState) {
    // ...
  }
}
```

### Updating the state

The state cannot be modified directly within a handling scope but can be updated by returning the intended changes from a handler. Returning an updated state is optional, and if omitted then no changes to the state will be persisted.

```typescript
import { Workflow } from '@node-ts/bus-core'

export class FulfilmentWorkflow extends Workflow<FulfilmentWorkflowState> {
  configureWorkflow (
    mapper: WorkflowMapper<FulfilmentWorkflowState, FulfilmentWorkflow>
  ): void {
    mapper
      .withState(FulfilmentWorkflowState)
      // ...
      .when(ItemShipped, 'emailReceipt')
  }
  
  // Workflow state is passed in as the second parameter to a workflow handler
  async emailReceipt (_: ItemShipped, state: FulfilmentWorkflowState) {
    return { status: 'sending-receipt' }
  }
}
```

### Discarding state

There are times when the workflow data shouldn't persist after a message has been handled. This is particularly relevant in cases where a workflow should only handle a message under certain circumstances.

For example, if your workflow is started by an **S3ObjectCreated** event, but should only create a new workflow if the object key is prefixed with `/documents`, then this can be achieved by returning `this.discardWorkflow()` in the workflow like so:

```typescript
import { Workflow, BusInstance } from '@node-ts/bus-core'

export class ProcessDocumentWorkflow extends Workflow<ProcessDocumentWorkflowState> {
  constructor (bus: BusInstance) {}
  configureWorkflow (
    mapper: WorkflowMapper<ProcessDocumentWorkflowState, ProcessDocumentWorkflow>
  ): void {
    mapper
      .withState(ProcessDocumentWorkflowState)
      .startedBy(S3ObjectCreated, 'readDocument')
  }
  
  async readDocument (event: S3ObjectCreated) {
    if (event.s3Key.indexOf('/documents') === 0 {
      await this.bus.send(new ReadDocument(event.s3Key))
    } else {
      // Ignore this message and avoid persisting the workflow state
      return this.discardWorkflow()
    }
  }
}
```
