Often in development variables doesn’t contain exactly what they supposed in particular when we put constraints to these variables. An typescript example: In this project a image gallery should display images in a slider on a webpage. The first image should be the current image displayed in a DOM-node, if the DOM-Node contains a image. There could be cases, where no current image exists. A very simplified implementation:


async function getImageUrls(): Promise {
  // read images
}
function getCurrentImageUrl(): string | null {
  return document.querySelector('#domNodeId').getAttribute('src');
}
function addToSlider(imageUrls: string[]): void {
  // ...
}
function moveSliderToImageUrl(imageUrl: string): void {
  // ...
}

let imageUrls = await getImageUrls();
addToSlider(imageUrls);
const currentImageUrl = getCurrentImageUrl();
if (currentImageUrl && !imageUrls.includes(currentImageUrl))
  imageUrls = [currentImageUrl].imageUrls
else if(currentImageUrl)
  moveSliderToImageUrl(currentImageUrl);

In this simplified implementation it’s obvious, that the current image isn’t added to the slider, when this url isn’t already included in the images retrieved by function getImageUrls. In the real implementation there was a lot more of code involved and this issue wasn’t obvious anymore, because when i wrote the line addToSlider(imageUrls); i assumed imageUrls already contains all urls without thinking on the current image url, which is added later.

Enhanced Types

How to avoid such situations? My idea was to create an enhanced type (in this case class ImageUrls) instead of a simple array.


class ImageUrls{
  #imageUrls: string[];
  #currentImageUrl: string;
  constructor(imageUrls: string[], currentImageUrl: string) {
    if (currentImageUrl)
      this.#imageUrls = [currentImageUrl].concat(imageUrls);
    else
      this.#imageUrls = imageUrls;
    this.#currentImageUrl = currentImageUrl;
  }
  get imageUrls(): string[] {
    return this.#imageUrls;
  }
  get currentImageUrl(): string {
    return this.#currentImageUrl;
  }
}

This type is lot more safer than a simple array. When creating an instance of this type, we already forced to provide the gallery image urls and the current image url. When we forget one of these variables, a compiler error is the consequence.


async function getImageUrls(): Promise {
  // read images
}
function getCurrentImageUrl(): Promise {
  return document.querySelector('#domNodeId').getAttribute('src');
}
function addToSlider(imageUrls: ImageUrls): void {
  // ...
}
function moveSliderToImageUrl(imageUrl: string): void {
  // ...
}

async function getInstance(): ImageUrls {
  const imageUrls = await getImageUrls();
  const currentImageUrl = getCurrentImageUrl();
  return new ImageUrls(imageUrls, currentImageUrl);
}

const imageUrls = await getInstance();
addToSlider(imageUrls);
if (imageUrls.currentImageUrl && imageUrls.includes(currentImageUrl))
  moveSliderToImageUrl(imageUrls.currentImageUrl);

Conclusion

The concept of enhanced types can be very powerful, when constraints are put to simple types. The enhanced type wraps the simple type and ensure the constraints aren’t violated. Although the example was written in typescript, the concept is language independent. It can be applied to ABAP and other programming languages, too.

Sara Sampaio

Sara Sampaio

Author Since: March 10, 2022

0 0 votes
Article Rating
Subscribe
Notify of
0 Comments
Inline Feedbacks
View all comments
0
Would love your thoughts, please comment.x
()
x