Basic type definition
These basic types match the ones that we get using the typeof operator in plain javascript, so no big deal here.
const myNumber: number = 5;
const myString: string = 'hello';
const myBoolean: boolean = true;
Functions
Typescript will always check for the number of parameters to be passed to match. But annotations are optional, since if we aren't in strict mode, it will infer any types for the parameters. This is not always a good thing.
//this will work
function greet(name) {
console.log("Hello, " + name.toUpperCase() + "!!");
}
//this will work too
function greet(name: string) {
console.log("Hello, " + name.toUpperCase() + "!!");
}
Also, the return type will be inferred, in this case void. But we could define it as well after the parenthesis:
function greet(name: string):void {
console.log("Hello, " + name.toUpperCase() + "!!");
}
As a rule of thumb, one must avoid explicitly defining types whenever typescript has inferred them right. But these depend a lot on the project and the team's decision. Some folks prefer a more strict approach, and this is useful not only to avoid errors but also for “self-documentation” of the code.
Object types
To define an object simply define each property annotations inside curly braces.
function printCoordinates (obj: {x:number, y:number}) {
//...
}
Working with functions is very likely that some of the arguments are undefined or could be optional. So keep in mind this, and put a “?” symbol.
function addToShoppingCart(obj: {code: number; name: string; description?: string }) {
//do something
}
💡 **Notice that you can put at the end of the property comma ( , ) or semi-colon ( ; ). They are both valid syntax.**
But take into account that typescript does not prevent the behavior that could happen at runtime, so you have to handle the possibility of the parameter coming undefined.
function addToShoppingCart(obj: {code: number; name: string; description?: string }) {
console.log(obj.description);
}
addToShoppingCart({ code: 123, name: 'stuff' });
//this will print to the console *undefined*
This example may be a harmful console log, but in a real-world scenario maybe this parameter is passed to another function or gets called one of the string methods, and then it would crash the application. For example:
function addToShoppingCart(obj: {
code: number;
name: string;
description?: string;
}) {
console.log(obj.description.toUpperCase());
}
addToShoppingCart({ code: 123, name: 'stuff' });
//this will throw an Error: *Cannot read properties of undefined (reading 'toUpperCase')*
So long story short, be careful with the optional properties and handle your undefines, that no one is gonna do it for you…
Union types
This is a helpful feature that lets you combine types to form new types. You’ll find this handy when a function parameter could have more than one type.
function findUser(userId: string | number, name: string) {
//...
}
Now the logical question will be, if userId could be both types, how would typescript know what methods to suggest? For example
function findUser(userId: string | number, name: string) {
userId.toLowerCase();
}
//This will give an Error: *Property 'toLowerCase' does not exist on type 'number'.*
Well, unfortunately, there is no fancy solution, we have to handle this with our own hands, coding some conditions and leveraging the typeof operator. This is called by the typescript documentation as narrowing.
function findUser(userId: string | number, name: string) {
if (typeof userId === 'string'){
userId.toLowerCase();
} else {
//...
}
}
So that's it for the common, not-so-crazy things that you will see in a typescript code. See you in the next article.
Top comments (0)