Skip to main content

Scripts

TypeScript is a powerful, statically-typed superset of JavaScript that can enhance your development workflow and help you write more reliable and maintainable code.

As all new internal code is, and will be, written in TypeScript, it is highly advised to use TypeScript in projects to remain compatible with the standard product.

This introduction covers the basic concepts of TypeScript, its advantages over JavaScript, and how to get started with TypeScript in your projects. Advanced features and in-depth tutorials are beyond the scope of this introduction but can be explored in further readings.

Overview

TypeScript is an open-source programming language developed by Microsoft. It builds on JavaScript by adding static type definitions, enabling developers to catch errors early in the development process and write more predictable code.

  • Static Typing: TypeScript introduces static types to JavaScript, allowing for compile-time type checking.
  • Enhanced IDE Support: TypeScript provides better code completion, navigation, and refactoring capabilities in modern IDEs.
  • ES6+ Features: TypeScript supports modern JavaScript features, including classes, modules, and async/await, and compiles them down to older JavaScript versions for compatibility.
  • Type Inference: TypeScript can infer types automatically, reducing the need for explicit type annotations.
  • Interfaces and Enums: TypeScript includes powerful features like interfaces and enums, which help in defining complex types and structures.

Why Use TypeScript?

  1. Improved Code Quality: TypeScript's type system helps catch errors during development, leading to fewer runtime errors and more robust code.
  2. Better Tooling: Enhanced tooling and editor support make the development experience smoother and more efficient.
  3. Scalability: TypeScript is particularly beneficial for large codebases, where type safety and maintainability are critical.
  4. Community and Ecosystem: A strong community and a rich ecosystem of type definitions for popular libraries (DefinitelyTyped) make integrating TypeScript into existing projects straightforward.

Guidelines / Instructions

  • Create TypeScript files with the .ts or .tsx extension.
  • Use type annotations to define the types of variables, function parameters, and return values.

Best Practices

Tips

Type Annotations: Use type annotations to ensure variables and function parameters have the correct types, which helps catch errors early.

let myVar: string = 'Hello, TypeScript';

function greet(name: string): void {
console.log(`Hello, ${name}`);
}

Use Interfaces and Types: Define interfaces and types to describe the shapes of objects and ensure consistency across your codebase.

interface User {
name: string;
age: number;
role: UserRole;
}

type UserRole = AdminRole | DefaultRole;

type AdminRole = 'admin';
type DefaultRole = 'default';

Common Pitfalls

Ignoring Type Errors: Avoid using the any type excessively, as it defeats the purpose of type safety.

// Avoid using any
let data: any = fetchData();

// Use appropriate types
let data: DataType = fetchData();

Improper Module Imports: Ensure you import modules correctly to avoid runtime errors.

// Correct import
import { LazyLoader } from '../global';

Examples / Use Cases

Type Annotations and Interfaces

interface ModalEvent {
type: string;
detail: { component: Modal };
}

class Modal {
modalElement: HTMLElement;
maskElement: HTMLElement;
animationDuration: number;
isShown: boolean;
isAnimating: boolean;

constructor(modalElement: HTMLElement, animationDuration: number = 200) {
this.modalElement = modalElement;
this.maskElement = document.createElement('div');
this.maskElement.className = 'modal-backdrop';
this.animationDuration = animationDuration;
this.isShown = false;
this.isAnimating = false;
}

dispatchEvent(eventType: string): void {
this.modalElement.dispatchEvent(new CustomEvent(eventType, { detail: { component: this }, bubbles: true }));
}

// Additional methods...
}

Using Enums and Constants

export const EVENTS: { [key: string]: string } = {
beforeOpen: 'cs.modal.beforeOpen',
beforeClose: 'cs.modal.beforeClose',
afterOpen: 'cs.modal.afterOpen',
afterClose: 'cs.modal.afterClose',
} as const;

class ModalManager {
static recentlyOpenedModals: Array<Modal> = [];

static addRecentlyOpenedModal(modal: Modal): void {
this.recentlyOpenedModals.push(modal);
}

static removeRecentlyOpenedModal(): void {
this.recentlyOpenedModals.pop();
}

static closeLastOpened(): void {
if (this.recentlyOpenedModals.length > 0) {
this.recentlyOpenedModals.at(-1).close();
}
}
}

Querying the Document

We use [data-cs-<>] selectors to keep the scripts separated from the styling. This approach ensures that our JavaScript targets specific elements without interfering with CSS classes, promoting a clear separation of concerns. The data-cs-<> selectors can be used in various forms, such as data-cs-toggle="modal" or standalone like data-cs-check-this.

document.addEventListener('DOMContentLoaded', () => {
const modalTriggers: NodeListOf<HTMLElement> = document.querySelectorAll('[data-cs-toggle="modal"]');

modalTriggers.forEach(trigger => {
trigger.addEventListener('click', (event: MouseEvent) => {
const targetSelector = trigger.getAttribute('data-cs-target');
const modalElement: HTMLElement = document.querySelector(targetSelector);

if (modalElement) {
event.preventDefault();
const modal = new Modal(modalElement);
modal.open();
}
});
});
});
document.addEventListener('DOMContentLoaded', () => {
const checkElements: NodeListOf<HTMLElement> = document.querySelectorAll('[data-cs-check-this]');

checkElements.forEach((element) => {
// Perform some action on the elements with data-cs-check-this
console.log('Element to check:', element);
});
});

In these examples:

  • We select all elements with the attribute [data-cs-toggle="modal"] or [data-cs-check-this].
  • We add event listeners or perform actions on these elements.
  • This approach ensures that our script is not tightly coupled with CSS classes, allowing for more flexible and maintainable code.

Writing a Custom Script

In this example, we import and initialize custom widgets in addition to the default widgets provided by the framework. This ensures modularity and reusability of code.

src/scripts/widgets.ts
import { widgets } from '@cloudsuite/mosaic/templates/scripts';
import customWidgets from './widgets/index';

document.addEventListener('DOMContentLoaded', () => {
widgets.init();
customWidgets.init();
});
src/scripts/widgets/index.ts
import { widget1 } from './widget-1';
import { widget2 } from './widget-2';
import { widget3 } from './widget-3';

const init = () => {
widget1.init();
widget2.init();
widget3.init();
};

export default { init };

Tools and Resources

Tools:

Resources:

  • TypeScript: Official TypeScript website with documentation and resources.
  • DefinitelyTyped: Repository of TypeScript type definitions for popular libraries.