feat(typings): Enhance typing support with withAppTypes and custom services throughout OHIF (#4090)

This commit is contained in:
Ibrahim authored and GitHub committed 2024-05-08 12:12:49 -04:00
1 parent b2cd0172d6
commit 374065bc3b
153 files changed
+842 -657

No files matched your search

+85
View File
@@ -0,0 +1,85 @@
---
sidebar_position: 10
sidebar_label: Global Types
---
# Extending App Types and Services in Your Application
This documentation provides an overview and examples on how to use and extend `withAppTypes`, integrate custom properties, and add services in the global namespace of the application. This helps in enhancing the application's modularity and extensibility.
## Overview of `withAppTypes`
The `withAppTypes` function is a TypeScript utility that extends the base properties of components or modules with the application's core service and manager types. It allows for a more flexible and type-safe way to pass around core functionality and custom properties.
### Using `withAppTypes`
`withAppTypes` can be enhanced using generics to include custom properties. This is particularly useful for passing additional data or configurations specific to your component or service.
### Extending with Custom Properties
You can extend `withAppTypes` to include custom properties by defining an interface for the props you need. For example:
```typescript
interface ColorbarProps {
viewportId: string;
displaySets: Array<any>;
colorbarProperties: ColorbarProperties;
}
export function Colorbar({
viewportId,
displaySets,
commandsManager, // injected type
servicesManager, // injected type
colorbarProperties,
}: withAppTypes<ColorbarProps>): ReactElement {
// Component logic here
}
```
In this example, `ColorbarProps` is a custom interface that extends the application types through `withAppTypes`.
## Typing the custom extensions's new services
Extensions can define additional services that integrate seamlessly into the application's global service architecture, and will be available on the ServicesManager for use across the application.
### Adding the extension's services Types
Declare your service in the global namespace and use it across your application as demonstrated below:
`extensions/my-extension/src/types/whatever.ts`
```typescript
declare global {
namespace AppTypes {
// only add if you need direct access to the service ex. AppTypes.MicroscopyService
export type MicroscopyService = MicroscopyServiceType;
// add to the global Services interface, and to withAppTypes
export interface Services {
microscopyService?: MicroscopyServiceType;
}
}
}
```
Doing the above adds the `microscopyService` to the global Services interface, which ServicesManager uses by default `public services: AppTypes.Services = {};` to type services, and is also used by withAppTypes to inject services into components.
You will also get access to the seperate services via `AppTypes.YourServiceName` in your application.
```typescript
export function CustomComponent({
servicesManager,
}: withAppTypes<CustomComponentProps>): ReactElement {
const { microscopyService } = servicesManager.services;
microscopyService.someMethod(); // auto completation available
}
```
```typescript
export function CustomComponent2(
microscopyService: AppTypes.MicroscopyService,
): ReactElement {
microscopyService.someMethod(); // auto completation available
}
```
@@ -36,11 +36,11 @@ for `OHIF-v3`.
// new service inside new extension
import MyNewService from './MyNewService';
export default function MyNewServiceWithServices(serviceManager) {
export default function MyNewServiceWithServices(servicesManager) {
return {
name: 'MyNewService',
create: ({ configuration = {} }) => {
return new MyNewService(serviceManager);
return new MyNewService(servicesManager);
},
};
}
@@ -146,12 +146,12 @@ and the logic for your service shall be
// Canonical name of upper camel case BackEndService for the class
import BackEndService from './BackEndService';
export default function WrappedBackEndService(serviceManager) {
export default function WrappedBackEndService(servicesManager) {
return {
// Note the canonical name of lower camel case backEndService
name: 'backEndService',
create: ({ configuration = {} }) => {
return new BackEndService(serviceManager);
return new BackEndService(servicesManager);
},
};
}
@@ -161,8 +161,8 @@ with implementation of
```ts
export default class BackEndService {
constructor(serviceManager) {
this.serviceManager = serviceManager;
constructor(servicesManager) {
this.servicesManager = servicesManager;
}
putAnnotations() {
@@ -28,7 +28,7 @@ We maintain the following non-ui Services:
![services-data](../../../assets/img/services-data.png)
> We have explained services and how to create a custom service in the
> [`ServiceManager`](../../managers/service.md) section of the docs
> [`ServicesManager`](../../managers/service.md) section of the docs
To recap: The simplest service return a new object that has a `name` property,
and `Create` method which instantiate the service class. The "Factory Function"
@@ -39,11 +39,11 @@ different for UI Services).
// extensions/customExtension/src/services/backEndService/index.js
import backEndService from './backEndService';
export default function WrappedBackEndService(serviceManager) {
export default function WrappedBackEndService(servicesManager) {
return {
name: 'myService',
create: ({ configuration = {} }) => {
return new backEndService(serviceManager);
return new backEndService(servicesManager);
},
};
}