Let's learn typescript: 002 - Everyday types
Published: 2024-01-04 22:40:12

### Basic type definition

These basic types match the ones that we get using the *typeof* operator in plain javascript, so no big deal here.

```tsx
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. 

```tsx
//this will work

function greet(name) {
  console.log("Hello, " + name.toUpperCase() + "!!");
}
```

```tsx
//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: 

```tsx
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.

```tsx
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.  

```tsx
function addToShoppingCart(obj: {code: number; name: string; description?: string }) {
  //do something
}
```

<aside>
💡 *****Notice that you can put at the end of the property comma ( , ) or semi-colon ( ; ). They are both valid syntax.*****

</aside>

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*.

```tsx
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:

```tsx
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.  

```tsx
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

```tsx
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*.

```tsx
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.