Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow for custom types and interfaces #1217

Closed
tobi-or-not-tobi opened this issue Feb 6, 2019 · 3 comments
Closed

Allow for custom types and interfaces #1217

tobi-or-not-tobi opened this issue Feb 6, 2019 · 3 comments

Comments

@tobi-or-not-tobi
Copy link
Contributor

Type safety is currently being hardcoded in the code base. This makes it impossible for customers to interact with custom types.
While this isn't an issue for the final production build, customers will have a hard time to extend

The following 2 examples illustrate the problem in our code base:

  1. Customise facade layer
    The facade layer contains a direct reference to the OCC models. Customers who have extended the product model, will not get any type safety for these new interfaces.
import { Product } from '../../occ/occ-models/occ.models';

export class ProductService {
  get(productCode: string, forceReload = false): Observable<Product> {}
}
  1. Custom components
    The component use the facade layer to get entities from the backend, and have added the typesafe models to the observed stream data. This is convenient both for the view logic as well as for business logic. Customers who extend this cannot benefit from custom types.
import { Product } from '@spartacus/core';

export class ProductDetailsComponent implements OnChanges {

  ngOnChanges() {
    this.product$ = this.productService.get(this.productCode)
  }

}

In order to provide for custom type safety, we should do the following:

  • move our interfaces to a library, i.e. @spartacus/types
  • reference the interfaces from the new library, both from the core and storefront library
  • add a tsconfig path configuration

Customers can then introduce custom interfaces which extend the default interfaces provided by Spartacus. This requires a path configuration, so that the typescript compiler knows where to load default and customer interfaces from.

An additional desired side effect of this approach is that we can update the typing library with each backend release. Having a specific version dependency will work towards a model where the dependency setup will dictate the backend version we're using.

@tobi-or-not-tobi tobi-or-not-tobi added this to To Do in Framed SPRINT via automation Mar 11, 2019
@Xymmer Xymmer added this to the BETA-0 milestone Mar 11, 2019
LTiger14 pushed a commit that referenced this issue Mar 27, 2019
@LTiger14 LTiger14 moved this from To Do to Code Review & Local QA in Framed SPRINT Mar 28, 2019
@LTiger14 LTiger14 removed their assignment Apr 2, 2019
@LTiger14
Copy link

LTiger14 commented Apr 2, 2019

Moving this back as it's not required before launch. Customers can create custom types by extending the default types.

interface CustomProduct extends Product {
  magic?: string;
}

@Injectable()
export class CustomProductService extends ProductService {
  get(productCode: string): Observable<CustomProduct> {
    const product: CustomProduct = { code: productCode, magic: 'Tobi 😉'};
    return of(product);
  }
}

@LTiger14 LTiger14 added this to To Do in Gladiators SPRINT via automation Apr 2, 2019
@LTiger14 LTiger14 removed this from To Do in Gladiators SPRINT Apr 2, 2019
@LTiger14 LTiger14 removed this from Code Review & Local QA in Framed SPRINT Apr 2, 2019
@Xymmer Xymmer modified the milestones: 1.0 Beta-0, 1.* Candidate, 2.* Candidate Apr 25, 2019
@Xymmer Xymmer modified the milestones: 2.x, 1.x Feb 7, 2020
@tobi-or-not-tobi
Copy link
Contributor Author

During the work on product scopes, @dunqan has done some more work around this topic. Unfortunately ng-packagr doesn't export the symbols in the root. If it would (something we'll investigate going forward), we could do the following:

declare module '@spartacus/core' {
  interface Product {
    magic?: string;
  }
}

Alternatively, or on top of this, we can alter our core layer, with generics, so that customers can invoke a service with custom type, i.e.:

constructor(protected currentProductService: CurrentProductService<MyProductType>) {}

The latter might give additional benefits, but will effect the entire core model.

@tobi-or-not-tobi
Copy link
Contributor Author

We continue this work in #7940

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants