TypeScript
TypeScript is a statically-typed superset of JavaScript that adds optional type annotations. It enhances JavaScript by enabling developers to catch errors early, improve code maintainability, and leverage modern ECMAScript features while compiling down to plain JavaScript.
Table of Contents
How is it different from JavaScript?
- TypeScript Functions vs JavaScript Functions
- What are the benefits of using TypeScript?
Ans: TypeScript is a superset of JavaScript that adds optional static typing and other features such as interfaces, classes, and enums. One of the main benefits of using TypeScript is that it can catch errors and bugs at compile time, rather than at runtime.
- How do you define a variable in TypeScript?
Ans: To declare a variable in TypeScript, you use the let or const keywords followed by the variable name and its type, like so: let myVariable: string = "Hello, world!";
- What is a type in TypeScript? Can you explain the different types of types in TypeScript?
In TypeScript, a type is a way of specifying the shape of a value, and there are several different types of types, including primitive types (such as string, number, and boolean), object types, and union types.
- How do you declare a function in TypeScript?
Ans: To declare a function in TypeScript, you specify the function's name, its parameters (including their types), and its return type, like so: function addNumbers(x: number, y: number): number { return x + y; }
JS Framework
- 1-way / 2-way binding
- lazy loading / eager loading
Class Inheritance
TypeScript Classes
publicprivateabstract
Super classes, (aka parent classes)
- allow for related objects to be grouped together so that they can inherit similar attributes.
TypeSript Interface
TypeScript Interfaces allow to specify properties and methods for an object.
interface Puppy {
name: string;
age: number;
};
const realPuppy: Puppy = {
name: 'Pikachu',
age: 1
};
const notRealPuppy: Puppy = {
says: 'meow' // Error: this is clearly not a puppy
}
Here, realPuppy is an implementation of the Puppy Interface.
Interface Inheritance
an interface that defines the common properties of our models:
export interface IHero {
id: string;
name: string;
photo?: string;
}
Now, let’s rewrite our previous 2 interfaces, using IHero as a parent interface
export interface IHuman extends IHero {
sex: string;
age: number;
health: number;
}
export interface ITransformer extends IHero {
wings: number;
wheels: number;
clan: string;
}
Now, both IHuman and ITransformer are descendant of IHero. This means that they both inherit all the properties of IHero. Any change made in IHero will automatically be available in all its descendant interfaces. Handful, isn’t it?
TypeScript Array Filter
"filter" is an Array method that allows you to generate a new array keeping only values that satisfy the condition
getGuestsComing() {
return this.guests.filter(guest => guest.coming);
}
TypeScript Path Alias
Auto Import? https://blog.bitsrc.io/short-typescript-import-paths-in-angular9-22ce34bd424d
import { Howl } from "howler";
import { Howl } from "./../../../node_modules/howler";
Sometimes you see a long import path like “../../../../../../../../../app/config/config.ts“, ugly right? Fear not, typescript path alias has come to the rescue.
Typescript aliases allow you to specify a word/alias for an absolute path in the application from which you can resolve paths from absolutely. This means that you can have an alias called @app for the absolute path “src/app” and if you wanted to import a module from “src/app/config/config.ts” you would import it like “@app/config/config.ts” from everywhere in your application! Now every other file that imports config.ts will have the exact same path, so if you want to move config.ts at some point, you would be able to just do a find and replace for the path.
default function parameter
var getTotal = function(price, tax = price * .07){
}
getTotal(undefined, 5.00)
TSConfig
The tsconfig.json file plays a vital role in an Angular web app by configuring how TypeScript gets compiled into JavaScript. It's essentially a rulebook for the TypeScript compiler.
Here's a breakdown of its key functions:
-
Specifying Compiler Options: It defines various settings for the TypeScript compiler, like the target JavaScript version (ES5, ES6, etc.), how errors are treated (strict null checks, allowing unreachable code), and module system (CommonJS, AMD, etc.).
-
Identifying Input Files: The file tells the compiler which TypeScript source files (
.tsfiles) to process during compilation. -
Controlling Output: It can specify the location for the generated JavaScript files (
.jsfiles) and how they are structured (single file or multiple files).
In essence, the tsconfig.json file dictates how your TypeScript code translates into consumable JavaScript for the browser to understand and run your Angular application.
Angular projects typically use the Angular CLI to set up the project structure, and this includes creating a default tsconfig.json file with common configurations. You can customize these configurations further to tailor the compilation process for your specific needs.
module property
"esnext"
useDefineForClassFields: false:
The default in modern TypeScript/ECMAScript is true. Setting it to false maintains older class field initialization behavior. Angular CLI might configure this differently now. If you haven't encountered issues, it might be okay, but aligning with the modern default (true) is generally recommended if possible, though it can require code adjustments if your class fields rely on the older behavior. Check the Angular 19 migration guide or a newly generated project's tsconfig.json for the recommended setting.
implements keyword
By using implements followed by the interface names (e.g., implements OnInit, OnChanges, ControlValueAccessor), the component class declares that it will provide implementations for the methods defined in those interfaces.
In Angular components, assertions and null checks are crucial practices for ensuring type safety and preventing runtime errors related to missing or unexpected data. Here's a breakdown of their roles in defining component properties:
1. Assertions:
- Assertions are a way to tell the TypeScript compiler that a variable or expression has a specific type, even if the compiler can't definitively determine it on its own.
- In Angular, assertions are commonly used with the non-null assertion operator (
!).
Why use assertions?
- Strict null checks: Angular often defaults to strict null checks, which means variables can't be null or undefined by default. This helps catch potential errors early in development.
- Initializing properties later: You might declare a component property but initialize it with a value later in the component's lifecycle (e.g., in
ngOnInit). Using the non-null assertion operator tells the compiler it's safe to use the property even before it's assigned a value.
Example:
public name!: string; // Declares name property with non-null assertion
ngOnInit() {
this.name = 'John Doe'; // Assigns value later
}
// In the template, you can safely use `name` without null checks:
<p>Hello, {{ name }}</p>
2. Null Checks:
- Null checks are explicit code statements that verify if a variable or expression might be null or undefined before using it.
Why use null checks?
- Prevent runtime errors: If you're unsure whether a property might be null (e.g., received from an external source), null checks prevent errors that would occur if you tried to use a null value.
- Improved code readability: Null checks make your code more explicit and easier to understand, especially when dealing with potentially nullable data.
Example (using optional chaining):
public user?: User; // Declares user property as optional
// In a method, you can perform a null check before accessing properties:
displayUserName() {
if (this.user) {
console.log(this.user.name); // Safe access using optional chaining
} else {
console.log('No user data available');
}
}
Choosing between assertions and null checks:
- Use assertions when you're confident a property will have a value eventually, but its initialization happens outside the current scope (e.g., after data is fetched).
- Use null checks when dealing with potentially null or undefined data, especially when the source of the data might be external or unreliable.
Best practices:
- Favor null checks over assertions for better code clarity and handling unexpected data scenarios.
- Consider using optional chaining (
?.) to safely access properties of potentially null or undefined objects. - If using assertions extensively, make sure your assumptions about data initialization are valid.
By effectively combining assertions and null checks, you write more robust and maintainable Angular components that handle data effectively and avoid runtime errors.