Understanding TypeScript
TypeScript is a type-based language. Much of its power comes with the ability to use static code analysis with JavaScript. This is possible thanks to the tools that exist inside the TypeScript environment.
These tools include the compiler, which can provide static analysis during development and after compilation, and the ECMAScript transpiler, which can make your code available to run on almost any JavaScript engine.
Let's get to know more about the language, and how it works.
Getting ready
To start, we will need to create an npm project. Open Terminal (macOS or Linux) or Command Prompt/PowerShell (Windows) and execute the following command:
> npm init -y
You also need to install TypeScript, so open Terminal (macOS or Linux) or Command Prompt/PowerShell (Windows) and execute the following command:
> npm install typescript --only=dev
Types
The main feature we get from using TypeScript is the types. In this section, we will learn about types, how to declare them, and how to use them.
These are some of the basic types in a statically typed language:
- String
- Number
- Boolean
- Arrays
- Tuple
- Enum
- Any
- Void
- Objects
Let's talk about some of these types and show how they can be used in TypeScript.
String
All the textual data on JavaScript will be treated as a string. To declare a string, we always need to surround it with double (") or single (') quotes, or the (`) grave accent, commonly known as a template string.
Declaring template strings inside text is not a problem with TypeScript. Template strings are a feature in ECMAScript that made it possible to add a variable inside a string without the need for concatenation:
const myText: string = 'My Simple Text';
const myTextAgain: string = "My Simple Text";
const greeting: string = `Welcome back ${myName}!`;
Number
In JavaScript, all numbers are floating-point values. In TypeScript, it's the same. Those numbers get a number type. In addition to the hexadecimal and decimal numbers, the binary and octal literals that were introduced in ECMAScript 2015 are treated like numbers too:
const myAge: number = 31;
const hexNumber: number = 0xf010d;
const binaryNumber: number = 0b1011;
const octalNumber: number = 0o744;
Boolean
The most basic type in the programming languages is the boolean values—a simple 1 or 0, and true or false. This is called a boolean:
const isTaskDone: boolean = false;
const isGreaterThen: boolean = 10 > 5;
Arrays
A group of elements in most of the languages is commonly called an array. In TypeScript, we can declare it in two different ways.
The most simple way is just to declare the type of the element followed by [] (square brackets) to denote that it is an array of the declared type:
const primeNumbers: number[] = [1, 3, 5, 7, 11];
Or, you can declare generically, using the Array<type> declaration. This is not the most common way used, but, depending on the code you are developing, you may need to use it:
const switchInstructions: Array<boolean> = [true, false, false, true];
Tuple
Tuples are a type of variable that has a specific structure. Structurally, a tuple is an array of two elements; both are a known type by the compiler and the user, but those elements don't need to have the same type:
let person: [string, number];
person = ['Heitor', 31];
console.log(`My name is ${person[0]} and I am ${person[1]} years old`);
If you try to access an element outside of the known indices, you will get an error.
Enum
Enums are similar to JavaScript objects, but they have some special attributes that help in the development of your application. You can have a friendly name for numeric values or a more controlled environment for the constants on the variables a function can accept.
A numeric enum can be created without any declaration. By doing this, it will start with the initial values of 0 and finish with the value of the final index number; or, you can get the name of the enum, passing the index of the enum value:
enum ErrorLevel {
Info,
Debug,
Warning,
Error,
Critical,
}
console.log(ErrorLevel.Error); // 3
console.log(ErrorLevel[3]); // Error
Or, an enum can be declared with values. It can be an initial declaration that the TypeScript compiler will interpret the rest of the elements as an increment of the first one, or an individual declaration:
enum Color {
Red = '#FF0000',
Blue = '#0000FF',
Green = '#00FF00',
}
enum Languages {
JavaScript = 1,
PHP,
Python,
Java = 10,
Ruby,
Rust,
TypeScript,
}
console.log(Color.Red) // '#FF0000'
console.log(Languages.TypeScript) // 13
Any
As JavaScript is a dynamic language, TypeScript needed to implement a type that has no defined value, so it implemented the any type. The most used case for the any type any is when using values that came from a third-party library. In that case, we know that we are dropping the type checking:
let maybeIs: any = 4;
maybeIs = 'a string?';
maybeIs = true;
The main use of the any type is when you are upgrading a legacy JavaScript project to TypeScript, and you can gradually add the types and validations to the variables and functions.
Void
As the opposite of any, void is the absence of the type at all. The most used case is with functions that won't return any values:
function logThis(str: string): void{
console.log(str);
}
Using void to type a variable is useless because it only can be assigned to undefined and null.
Objects
An object in TypeScripts has a special form of declaring because it can be declared as an interface, as a direct object, or as a type of its own.
Declaring an object as an interface, you have to declare the interface before using it, all the attributes must be passed, and the types need to be set:
interface IPerson {
name: string;
age: number;
}
const person: IPerson = {
name: 'Heitor',
age: 31,
};
Using objects as direct inputs is sometimes common when passing to a function:
function greetingUser(user: {name: string, lastName: string}) {
console.log(`Hello, ${user.name} ${user.lastName}`);
}
And finally, they are used for declaring a type of object and reusing it:
type Person = {
name: string,
age: number,
};
const person: Person = {
name: 'Heitor',
age: 31,
};
console.log(`My name is ${person.name}, I am ${person.age} years old`);
Functions
In TypeScript, one of the most difficult types to declare is a function. It can get very complex in a just simple concatenation of the functional chain.
Declaring a function in TypeScript is a composition of the parameters that the function will receive and the final type that the function will return.
You can declare a simple function inside a constant, like this:
const sumOfValues: (a:number, b:number): number = (a: number, b: number): number => a + b;
A more complex function declared inside a constant can be declared like this:
const complexFunction: (a: number) => (b:number) => number = (a: number): (b: number) => number => (b: number): number => a + b;
When declaring a function as a normal function, the way to type it is almost the same as in a constant way, but you don't need to declare that the functions are a function. Here is an example:
function foo(a: number, b:number): number{
return a + b;
}
Interfaces
TypeScript checks that the values of variables are the correct type and the same principle is applied to classes, objects, or contracts between your code. This is commonly known as "duck typing" or "structural sub-typing". Interfaces exist to fill this space and define these contracts or types.
Let's try to understand an interface with this example:
function greetingStudent(student: {name: string}){
console.log(`Hello ${student.name}`);
}
const newStudent = {name: 'Heitor'};
greetingStudent(newStudent);
The function will know that the object has the property name on it and that it's valid to call it.
We can rewrite it with the interface type for better code management:
interface IStudent {
name: string;
course?: string;
readonly university: string;
}
function greetingStudent(student: IStudent){
console.log(`Hello ${student.name}`);
if(student.course){
console.log(`Welcome to the ${student.course}` semester`);
}
}
const newStudent: IStudent = { name: 'Heitor', university: 'UDF' };
greetingStudent(newStudent);
As you can see, we have a new property called course that has a ? declared on it. This symbolizes that this property can be nulled or undefined. It's called an optional property.
There is a property with a read-only attribute declared. If we try to change after it's declared on the variable creation, we will receive a compile error because it makes the property read-only.
Decorators
A new feature was introduced in ECMAScript 6—classes. With the introduction of these, the usage of decorators was made possible on the JavaScript engine.
Decorators provide a way to add both annotations and meta-programming syntax to class declarations and its members. As it's in a final state of approval on the TC-39 committee (where TC stands for Technical Committee), the TypeScript compiler already has this available to be used.
To enable it, you can set the flags on the tsconfig.json file:
{
"compilerOptions": {
"target": "ES5",
"experimentalDecorators": true
}
}
Decorators are a special kind of declaration that can be attached to a class, method, accessor property, or parameter. They are used in the form of @expression, where the expression is a function that will be called at runtime.
An example of a decorator that can be applied to a class can be seen in the following code snippet:
function classSeal(constructor: Function) {
Object.seal(constructor);
Object.seal(constructor.prototype);
}
When you create this function, you are saying that the object of the constructor and the prototype of it will be sealed.
To use it inside a class is very simple:
@classSeal
class Animal {
sound: string;
constructor(sound: string) {
this.sound = sound;
}
emitSound() {
return "The animal says, " + this.sound;
}
}
These are just some examples of decorators and their powers to help you with the development of object-oriented programming (OOP) with TypeScript.
In conclusion
In summary, types are just a way to make our life easier in the process of development with TypeScript and JavaScript.
Because JavaScript is a dynamic language and doesn't have a static type, all the types and interfaces declared in TypeScript are strictly used just by TypeScript. This helps the compiler catch errors, warnings, and the language server to help the integrated development environment (IDE) on the development process to analyze your code as it is being written.
This is a basic introduction to TypeScript, covering the basics of the typed language, and how to understand and use it. There is much more to learn about its use, such as generics, modules, namespaces, and so on.
With this introduction, you can understand how the new Vue 3 core works and how to use the basics of TypeScript in your project, and take advantage of the typed language on your project.
There is always more knowledge to find on TypeScript, as it is a growing "language" on top of JavaScript and has a growing community.
Don't forget to look at the TypeScript documentation to find out more about it and how it can improve your code from now on.
See also
You can find more information about TypeScript basic types at https://www.typescriptlang.org/docs/handbook/basic-types.html.
You can find more information about TypeScript functions at https://www.typescriptlang.org/docs/handbook/functions.html.
You can find more information about TypeScript enums at https://www.typescriptlang.org/docs/handbook/enums.html.
You can find more information about TypeScript advanced types at https://www.typescriptlang.org/docs/handbook/advanced-types.html.
You can find more information about TypeScript decorators at https://www.typescriptlang.org/docs/handbook/decorators.html.
View a cheatsheet on TypeScript types at https://rmolinamir.github.io/typescript-cheatsheet/#types.