I liked the answer from Roland Ewald since he described with a very simple use case of type alias, and for more detail introduced a very nice tutorial.
However, since another use case is introduced in this post named type members, I would like to mention the most practical use case of it, which I liked very much:
(this part is taken from here:)
Abstract Type:
type T
T above says that this type that is going to be used, is unknown yet, and depending on the concrete subclass, it will be defined.
The best way always for understanding the programming concepts is providing an example:
Suppose you have the following scenario:

Here you will get compilation error, because eat method in classes Cow and Tiger do not override the eat method in class Animal, because their parameter types are different. It's Grass in class Cow, and Meat in class Tiger vs. Food in class Animal which is super class and all subclasses must conform.
Now back to type abstraction, by the following diagram and simply adding a type abstraction, you can define the type of the input, in according subclass itself.

Now look at following codes:
val cow1: Cow = new Cow
val cow2: Cow = new Cow
cow1 eat new cow1.SuitableFood
cow2 eat new cow1.SuitableFood
val tiger: Tiger = new Tiger
cow1 eat new tiger.SuitableFood // Compiler error
Compiler is happy and we improve our design. We can feed our cow with cow.SuitableFood and compiler prevent us with feeding out cow with the food which is suitable for Tiger. But what if we want to make difference between the type of cow1 SuitableFood and cow2 SuitabeFood. In another word, it would be very handy in some scenarios if the path by which we reach to the type (of course via object) does basically matter. Thanks to the advanced features in scala, it is possible:
Path-dependent types:
Scala objects can have types as members. The meaning of the type, depends on the path you use to access it. The path is determined by the reference to an object (aka an instance of a class).
In order to implement this scenario, you need to define class Grass inside the Cow, i.e., Cow is the outer class and Grass is the inner class. The structure will be like this:
class Cow extends Animal {
class Grass extends Food
type SuitableFood = Grass
override def eat(food: this.SuitableFood): Unit = {}
}
class Tiger extends Animal {
class Meat extends Food
type SuitableFood = Meat
override def eat(food: this.SuitableFood): Unit = {}
}
Now if you try to compile this code:
1. val cow1: Cow = new Cow
2. val cow2: Cow = new Cow
3. cow1 eat new cow1.SuitableFood
4. cow2 eat new cow1.SuitableFood // compilation error
On line 4 you will see an error because Grass is now an inner class of Cow, therefore, to create an instance of Grass, we need a cow object and this cow object determines the path. So 2 cow objects give rise to 2 different path.
In this scenario, cow2 only wants to eat food especially created for it. So:
cow2 eat new cow2.SuitableFood
Now everybody is happy :-)