Skip to content

Latest commit

 

History

History
95 lines (65 loc) · 5.35 KB

type-augmentation.md

File metadata and controls

95 lines (65 loc) · 5.35 KB
title feature
Extending Built-In Models
name spa_version cx_version
Extending Built-In Models
2.1
1905

{% capture version_note %} {{ site.version_note_part1 }} 2.1 {{ site.version_note_part2 }} {% endcapture %}

{% include docs/feature_version.html content=version_note %}

TypeScript gives developers a lot of confidence and safety, and speeds up development and library discovery. Where possible, Spartacus leverages the possibilities offered by TypeScript to provide a better developer experience. With Spartacus 2.1, you can take advantage of TypeScript's type augmentation capabilities.

Spartacus has already typed most of the common objects that are used across the whole codebase, such as Cart and Product (and many more). However, the shape of these models was defined by Spartacus, which prevented you from adding properties to already-defined models. This could lead to difficulties working with the extra fields you may have needed in your customizations.

In future releases of Spartacus, more top-level exports will be added, which will allow you to augment them.

For more information about type augmentation in general, see Module Augmentation in the TypeScript documentation.

Exporting Type for Augmentation

The models that are most frequently customized are currently placed in @spartacus/core. The following is an example of module augmentation on a newly-added CostCenter model that is used in B2B Checkout:

export interface CostCenter {
  active?: boolean;
  code?: string;
  name?: string;
  unit?: B2BUnit;
}

In the core library, in the projects/core/public_api.ts file that defines the public API, Spartacus exports models directly, meaning there is no re-export. The following is an example:

export { CostCenter } from './src/model/org-unit.model';

That is all that is required to expose the model for augmentation.

Note: This approach is required because of the current limitations of Typescript. See TypeScipt issues #9532 and #18877 for more information.

Note: If there are models that you would like to expose for augmentation, you can submit issues and pull requests indicating which models you would like to expose.

Augmenting Modules

Now that the CostCenter can be augmented, you can alter its shape to fit your requirements. Let's say you need to display the originalCode field to users. Even if you have already adjusted the endpoint configuration and entity normalizers, TypeScript still does not automatically suggest that the originalCode key is also present on that model. To add it to the TypeScript type, you have to declare a new property on a CostCenter interface. The following is an example:

declare module '@spartacus/core' {
  interface CostCenter {
    originalCode?: string;
  }
}

The module name @spartacus/core must be set according to the same value that you use to reference the type. In this case, the module is @spartacus/core, and you import the type as follows:

import { CostCenter } from '@spartacus/core'

From now on, when you work on an object of type CostCenter, the TypeScript compiler will suggest the originalCode property in autocomplete, and will allow you to define objects on this type normally, without having to hack the TypeScript with as CostCenter declarations.

Note: You should only add optional properties to a module when you augment it. Do not add required properties because new objects of this type may be constructed in the library code, and then you will get errors from the TypeScript compiler that there are missing properties in objects of augmented type.

Augmentation in Feature Libraries

You can also apply module augmentation techniques to feature libraries. To take an example from the Spartacus development team, we needed a CostCenter object for the @spartacus/my-account library and the OrganizationModule. However, we needed more properties than were defined in the @spartacus/core library.

Accordingly, we created a new cost-center.model.ts file where we could apply module augmentation. As with regular module augmentation, when augmenting a feature library, all properties should be optional. The following is an example:

import { Currency } from '@spartacus/core';

declare module '@spartacus/core' {
  interface CostCenter {
    activeFlag?: boolean;
    currency?: Currency;
  }
}

Next, we needed to reference this file. In the file that exposes all the organization models that are in the public API (feature-libs/my-account/organization/core/model/index.ts), we added an import of this augmented model. The following is an example:

import './cost-center.model';

After that, anyone can safely use the new properties in the @spartacus/my-account library, as well as in the app build that is based on this library. You can also augment the module in the app with your own properties. All these declarations are combined together, and in your application, you can use all the properties that are declared in @spartacus/core, @spartacus/my-account, and in your module augmentation.

Note: In each module augmentation declaration, you use the module name of the library that exposes the base type.