DEV Community

Cover image for Typescript: Type Aliases and Union
Jatin Sharma
Jatin Sharma

Posted on • Updated on

Typescript: Type Aliases and Union

In this article, you will learn about Type Aliases and how you can define your own types in typescript and use that in functions or classes as well. Along with Type Aliases, I have also explained how you can use Union to create multiple type variables which means that one variable can have multiple types at once.

This is going to be a full series of typescript where you will learn from basic topics like string, boolean to more complex like Type Aliases, enums, Interface, generics, etc.

Table of Contents

Type Aliases

We can use the objects as shown in the previous example but what if there are 100s of functions that need the same data of the user then you'll be typing for all of them separately that's where Type comes into play. Let's look at the old example and how we can use type to make it reusable.

type User = {
  email: string;
  password: string;
};

// ✅ CORRECT
// Passsing Object Type Aliases
function signUp(user: User){}

// ✅ It's the correct way to call
signUp({email: "some@hello.com", password: "1233"})

// ❌ ERROR : 'name' does not exist in type 'User'
signUp({email: "some@hello.com", password: "1233", name: "Sam"})

// ✅ You can pass extra information by using a variable
let userObj =  {email:  "some@hello.com", password:  "1233", name:  "Sam"}
signUp(userObj)
Enter fullscreen mode Exit fullscreen mode

You can use a type alias to give a name to any type at all, not just an object type. For example:

type ID = number;
let userId: ID = 111; // ✅ CORRECT
Enter fullscreen mode Exit fullscreen mode

I guess you get the point that we use type to define the actual type of the variable. It can be used anywhere.

Readonly and Optional

readonly means that the user or anyone cannot manipulate that variable, for example id optional means that these parameters are optional which we have looked at before in functions.

Let's take an example of User where the user will have three properties id, email, and name.

// Defining the User type
type User = {
    readonly id : string,
    name: string,
    email: string,
}

// Now Let's create a user variable using the above type:
let myUser:User = {
    id : "3947394",
    name: "harry",
    email: "h@harry.com",
}

// Now I'll assign the values to the myUser object

// ✅ CORRECT
myUser.name = "Potter";
myUser.email = "hello@harry.com";

// ❌ ERROR: Cannot assign to 'id' because it is a read-only property
myUser.id = "121324";
Enter fullscreen mode Exit fullscreen mode

Now, let's take a look at the optional:

// Defining the User type
type User = {
    readonly id : string,
    name: string,
    email: string,
    dob?: string    // optional
}

// ✅ CORRECT
let user1: User = {
    id : "3947394",
    name: "harry",
    email: "h@harry.com",
    dob: "02/12/1998"
}

// ✅ CORRECT
let user2: User = {
    id : "3947394",
    name: "harry",
    email: "h@harry.com",
}
Enter fullscreen mode Exit fullscreen mode

Intersection in `type`

You can combine two or more types using &. You can do that as shown in the following code:

type User = {
    readonly id : string,
    name: string,
    email: string,
}

type Admin = User & {
    key: string, 
}

// You can use Admin like this:
let newAdmin: Admin = {
  id: "3KD5D874",
  name: "Lucifer",
  email: "lucifer@hell.com",
  key: "Oh my me!",
};
Enter fullscreen mode Exit fullscreen mode

Now Admin will have User properties as well as shown in the above code.

Type Aliases in Functions

As I have defined multiple types in the above code. These are the custom type that you can even use in functions in form of Parameters or Return Values. You just need to define the type and then pass it as the parameter.

Type Aliases as a function parameter

 type User = {
    name: string,
    email: string,
    password: string, 
}
// You can use optional variables as well 

// Function that will add user to the database
function addUser(user: User){
    // do some database opertion
}


// ❌ ERROR:  Property 'password' is missing in type '{ name: string; email: string; }' but required in type 'User'
addUser({name: "Rao", email: "rao@gmail.com")
// ✅ CORRECT
addUser({name: "Rao", email: "rao@gmail.com", password: "12345678"})
Enter fullscreen mode Exit fullscreen mode

Type Aliases as a function return value

type User = {
    _id: string 
    name: string,
    email: string,
}

// ✅ CORRECT
function loginUser(id: string): User {
    // performing some operation
    return {_id: id, name: "Joe", email:"joe@gmail.com"}
}

// ❌ ERROR: Property 'email' is missing
function loginUser(id: string): User {
    // performing some operation
    return {_id: id, name: "Joe"}
}
Enter fullscreen mode Exit fullscreen mode

Union

In Typescript, you can define more than one type of variable. You can do that by just putting (|) in the middle of two types. Let me show you what I am saying:

let id: string | number;

id = 123;           // ✅
id = "34398493";    // ✅
Enter fullscreen mode Exit fullscreen mode

Both the example shown in the above code is correct. Let's take a little more complex example to understand how it works:

type User = {
    name: string,
    id : number
}

type Admin ={
    username: string,
    id: number,
    key: number,
}

let newUser : User | Admin;

// ✅ CORRECT
newUser = {name: "John", id: 123};
newUser = {username : "j333", id : 123, key: 345};
newUser = {name: "j333", id : 123, key: 345};

// ❌ ERROR: Property 'key' is missing
newUser = {username : "j333", id : 123};
Enter fullscreen mode Exit fullscreen mode

Union in Functions

You can also use these with function parameters as shown below:

// ✅ It works and id have string and number type
function setUserId(id: string | number){
    console.log(id);
}

// ❌ ERROR : 
// What if we do like this:
function setUserId(id: string | number ){
    id.toLowerCase()  // ❌ ERROR: Property 'toLowerCase' does not exist on type 'number
}
Enter fullscreen mode Exit fullscreen mode

Now the above code will show you an error because id has two types string and number. The string can be converted to lowercase but the number can't. That's why it is showing you the error. You can use the conditional statement to do your desired stuff. Such as:

function setUserId(id: string | number ){
    if (typeof id === "string") {
        id.toLowerCase()
    }
    // do other things
}
Enter fullscreen mode Exit fullscreen mode

Now it won't give you any errors because we are making sure that toLowerCase() only calls when the id is a string.

Union in Array

In the array section, we discussed that we can set an array type with two methods. But the issue with that is What if we want an array that has multiple types of values such as string and number then what do we do? The answer is Union. Now let's take a look at how you do it:

// You might be thinking like this
// Nah ❌ you can't do like that
let newArray: number[] | string[] = [1,2, "hello"];

// ✅ Correct way to define the array with multiple type is:
let newArray: (number | string)[] = [1,2, "hello"];
Enter fullscreen mode Exit fullscreen mode

Special Case for Union

Now imagine you are working on CSS Framework and you are designing a Button. And you are asking the user to tell what size should button have. Now you can use the variable type as string but the user can type anything, right? Let's understand this via an example:

// ❌ WRONG APPROACH
let ButtonSize: string;

ButtonSize = "big";
ButtonSize = "medium";
ButtonSize = "don't know";  // that's why don't use this

// ✅ CORRECT APPROACH
let ButtonSize : "sm" | "md" | "lg" | "xl";

ButtonSize = "sm";
ButtonSize = "md";
ButtonSize = "lg";
ButtonSize = "xl";

// ❌ ERROR: Type 'large' is not assignable to type
ButtonSize = "large";
Enter fullscreen mode Exit fullscreen mode

As you saw at the end of the above code the typescript restricts you from assigning large to ButtonSize. It only accepts special types defined by you for the button.

Your Task

Now, It's your turn to create something. So, for that You have to create a type for a User that will have the following properties:

  • _id: a string representing a unique identifier for the user

  • name: a string representing the user's name

  • posts: an array of objects, each representing a post made by the user, with properties id, title, and body

  • comments: an array of objects, each representing a comment made by the user, with properties id, postId, and body.

Wrapping up

In this article, I explained what is Type Aliases and how you can define your own types in typescript and use that in functions or classes as well. Along with Type Aliases, I have also explained how you can use Union to create multiple type variables which means that one variable can have multiple types at once.

This is a series of Typescript that will help you to learn Typescript from the scratch. If you enjoyed this article, then don't forget to give ❤️ and Bookmark 🏷️for later use and if you have any questions or feedback then don't hesitate to drop them in the comments below. I'll see in the next one.

Connect with me

Twitter GitHub LinkedIn Instagram Website Newsletter Support

Top comments (2)

Collapse
 
josejuansanz profile image
Jose

Nice article!

I think there is an error in the example you wrote on the Union in Functions section, it should be

function setUserId(id: string | number ){
    if (typeof id === "string") {
        id.toLowerCase()
    }
    // do other things
}
Enter fullscreen mode Exit fullscreen mode
Collapse
 
j471n profile image
Jatin Sharma

Thanks man for catching this, it was a typo error. 👐