Joshua Yates

Joshua Yates

1595389748

TypeScript Types Explained – A Mental Model to Help You Think in Types

One day I came across this tweet from Lari Mazza:

As a software engineer who learned Python, Ruby, Javascript, and Clojure first, when I tried C++ it was a horror movie. I couldn’t do much, and it was so counterproductive and frustrating. Maybe because I was doing everything wrong and I didn’t understand types the right way.

But even though I had so many problems, I could implement a bunch of algorithms and data structures.

Now that I’m using more and more Typescript in my day-to-day job and my side projects, I feel I’m more prepared to confront types. Actually, not confront, but use them in my favor.

This post is my attempt to help developers think more in types and understand this mental model.

Thinking in JavaScript types

If you’re here, you’ve probably heard that Typescript is a superset of Javascript. If not, great, you just learned something new today. YAY!

Typescript is a superset because any Javascript code is valid in Typescript, syntactically speaking. It may or may not compile depending on the Typescript compiler configuration. But in terms of syntax, it works just fine.

This is why you can migrate Javascript to Typescript progressively by just replacing the .js extension with the .ts. Everything will be without type declarations (the any type), but that’s another story.

Also, if you code in Javascript - or any other programming language - you probably think in types:

  • “Hm, it is a list of integers, so I’ll need to filter only the even numbers and return a new list”
  • “This is an object, but I just need to get this string value from the property X”
  • “This function receives two parameters. Both A and B are integers and I want to sum them”

Yeah, you get the idea. We think in types. But they are just in our heads. We constantly think about them because we need to know how to handle, parse, or modify data. We need to know which methods we are allowed to use in this object type.

To give a more concrete example, imagine you want to sum the price of all products. A product object looks like this:

const product = {
  title: 'Some product',
  price: 100.00,
};

But now with a list of products:

const products = [
  {
    title: 'Product 1',
    price: 100.00,
  },
  {
    title: 'Product 2',
    price: 25.00,
  },
  {
    title: 'Product 3',
    price: 300.00,
  }
];

Ok! Now we want a function to sum all the products prices.

function sumAllPrices(products) {
  return products.reduce((sum, product) => sum + product.price, 0);
};

sumAllPrices(products); // 425

Just receive the products as the argument and reduce all product prices. Javascript works just fine. But while building this function you start to think about the data and how to handle it properly.

The first part: products as an argument. Here you just think: “well, we’re receiving a list of some objects”. Yeah, in our heads the products are a list. This is why we can think of using the reduce method. It is a method from the Array prototype.

Then we can think about the object in detail. We know that the product object has a price property. And this property is a number. This is why we can do product.price and sum with the accumulator.

Recapping:

  • products is a list of objects.
  • As a list, we can use the reduce method, as this method is a member of the Array prototype.
  • The produce object has some properties. One of them is the price, which is a number.
  • As a number property, we can use it to sum with the reduce accumulator.
  • We wanted to return a number, the sum of all products prices.

We are always thinking of data types, we just need to add the type annotations to make it more explicit and ask the compiler for help. Our memory is limited and the compilers are here to help us, humans.

The type system will not only make our data more consistent, but it can also provide autocompletion for data types. It knows the types, so it can show the members for the data. We will take a look at this idea later. Here I just wanted to show that we think in types in our heads.

Simples Types & Simple Uses

So we are ready to use some strongly typed programming languages like Typescript. We simply need to explicitly add type annotations to our data structures. It’s simple, right?

But sometimes it’s not that easy (usually it’s not easy when you come from dynamically typed languages. You feel unproductive. It feels like a battle against types). The idea here is to make this learning curve smoother and more fun.

Here we will see many examples of how to use types in Typescript. We’ll start with easy and silly examples and progressively make it more complex while designing the mental model to think in types.

As in Javascript, Typescript also has basic data types like number, string, boolean, null, etc. You can find all the basic data types in the Typescript Docs.

With these units of data, we can make our programs more useful. To be more practical, let’s get a simple example. A sum function.

How does it work in Javascript?

function sum(a, b) {
  return a + b;
}

Everything ok? Good.

Now let’s use it:

sum(1, 2); // 3
sum(2, 2); // 4
sum(0, 'string'); // '0string'   WTF!

The first two calls are what we expect to happen in our system. But Javascript is very flexible, it lets us provide any value to this function.

The last call is bizarre. We can call with a string, but it will return an unexpected result. It doesn’t break in development, but it will result in strange behavior in runtime.

What do we want? We want to add some constraints to the function. It will only be able to receive numbers. That way, we narrow the possibility of having unexpected behaviors. And the function return type is also a number.

function sum(a: number, b: number): number {
  return a + b;
}

Great! It was very simple. Let’s call again.

sum(1, 2); // 3
sum(2, 2); // 4
sum(0, 'string'); // Argument of type '"string"' is not assignable to parameter of type 'number'.

As we type annotate our function, we provide information to the compiler to see if everything is correct. It will follow the constraints we added to the function.

So the first two calls are the same as in Javascript. It will return the correct calculation. But in the last one we have an error in compile time. This is important. The error now happens in compile time and prevents us from shipping incorrect code to production. It says that the string type is not part of the set of values in the number type universe.

For basic types, we just need to add a colon followed by the type definition.

const isTypescript: boolean = true;
const age: number = 24;
const username: string = 'tk';

Now let’s increase the challenge. Remember the product object code we wrote in Javascript? Let’s implement it again, but now with the Typescript mindset.

Just to remember what we are talking about:

const product = {
  title: 'Some product',
  price: 100.00,
};

This is the product value. It has a title as string and the price as number. For now, this is what we need to know.

The object type would be something like this:

{ title: string, price: number }

And we use this type to annotate our function:

const product: { title: string, price: number } = {
  title: 'Some product',
  price: 100.00,
};

With this type, the compiler will know how to handle inconsistent data:

const wrongProduct: { title: string, price: number } = {
  title: 100.00, // Type 'number' is not assignable to type 'string'.
  price: 'Some product', // Type 'string' is not assignable to type 'number'.
};

Here it breaks down into two different properties:

  • The title is a string and should not receive a number.
  • The price is a number and should not receive a string.

The compiler helps us to catch type errors like that.

We could improve this type annotation by using a concept called Type Aliases. It’s a way to create a new name for a specific type.

In our case, the product type could be:

type Product = {
  title: string;
  price: number;
};

const product: Product = {
  title: 'Some product',
  price: 100.00,
};

It’s better to visualize the type, add semantics, and maybe reuse in our system.

Now that we have this product type, we can use it to type the products list. The syntax looks like this: MyType[]. In our case, Product[].

const products: Product[] = [
  {
    title: 'Product 1',
    price: 100.00,
  },
  {
    title: 'Product 2',
    price: 25.00,
  },
  {
    title: 'Product 3',
    price: 300.00,
  }
];

Now the function sumAllPrices. It will receive the product and return a number, the sum of all product prices.

function sumAllPrices(products: Product[]): number {
  return products.reduce((sum, product) => sum + product.price, 0);
};

This is very interesting. As we typed the product, when we write product., it will show the possible properties we can use. In the product type case, it will show the properties price and title.

sumAllPrices(products); // 425
sumAllPrices([]); // 0
sumAllPrices([{ title: 'Test', willFail: true }]); // Type '{ title: string; willFail: true; }' is not assignable to type 'Product'.

Passing the products will result in the value 425. An empty list will result in the value 0. And if we pass an object with a different structure - Typescript has a structural type system and we will dig deep into this topic later - the compiler will throw a type error telling that the structure is not part of the Product type.

Structural Typing

Structural typing is a type of type compatibility. It’s a way to understand the compatibility between types based on its structure: features, members, properties. Some languages have type compatibility based on the names of the types, and it’s called nominal typing.

For example, in Java, even if different types have the same structure, it will throw a compile error because we are using a different type to instantiate and define a new instance.

class Person {
  String name;
}

class Client {
  String name;
}

Client c = new Person();  // compiler throws an error
Client c = new Client();  // OK!

In nominal type systems, the relevant part of a type is the name, not the structure.

Typescript, on another hand, verifies the structural compatibility to allow or not specific data. Its type system is based on structural typing.

The same code implementation that crashes in Java, would work in Typescript.

class Person {
  name: string;
}

class Client {
  name: string;
}

const c1: Client = new Person(); // OK!
const c2: Client = new Client(); // OK!

We want to use the Client type, and it has the property name, to point to the Person type. It also has the property type. So Typescript will understand that both types have the same shape.

But it is not only about classes, but it works for any other “object”.

const c3: Client = {
  name: 'TK'
};

This code compiles too because we have the same structure here. The typescript type system doesn’t care about if it is a class, or an object literal if it has the same members, it will be flexible and compile.

But now we will add a third type: the Customer.

class Customer {
  name: string;
  age: number;
};

It not only has the name property, but also the age. What would happen if we instantiate a Client instance in a constant of type Customer?

const c4: Customer = new Client();

The compiler will not accept that. We want to use the Customer, that has name and age. But we are instantiating the Client that has only the name property. So it doesn’t have the same shape. It will cause an error:

Property 'age' is missing in type 'Client' but required in type 'Customer'.

The other way around would work because we want Client, and Customer has all the properties (name) from Client.

const c5: Client = new Customer();

It works fine!

We can go on for enums, object literals, and any other type, but the idea here is to understand that the structure of the type is the relevant part.

Runtime and Compile time

This is a much more complex topic in programming language theory, but I wanted to give some examples to distinguish runtime from compile time.

Basically, the runtime is the execution time of a program. Imagine your backend receiving data from a frontend form page, handling this data, and saving it. Or when your frontend is requesting data from a server to render a list of Pokemons products.

Compile time is basically when the compiler is executing operations in the source code to satisfy the programming language’s requirements. It can include type checking as an operation, for example.

Compile time errors in Typescript, for example, are very related to the code that we wrote before:

  • When the type is missing property: Property 'age' is missing in type 'Client' but required in type 'Customer'.
  • When the type doesn’t match: Type '{ title: string; willFail: true; }' is not assignable to type 'Product'.

Let’s see some examples to have a better understanding.

I want to write a function to get the index of a part of the passed programming language.

function getIndexOf(language, part) {
  return language.indexOf(part);
}

It receives the language and the part that we will look for to get the index.

getIndexOf('Typescript', 'script'); // 4
getIndexOf(42, 'script'); // Uncaught TypeError: language.indexOf is not a function at getIndexOf

When passing a string, it works fine. But passing a number, we got a runtime error Uncaught TypeError. Because a number doesn’t have an indexOf function, so we can’t really use it.

But if we give type information to the compiler, in compile time, it will throw an error before running the code.

function getIndexOf(language: string, part: string): number {
  return language.indexOf(part);
}

Now our program knows that it will need to receive two strings and return a number. The compiler can use this information to throw errors when we get a type error… before runtime.

getIndexOf('Typescript', 'script'); // 4
getIndexOf(42, 'script'); // Argument of type '42' is not assignable to parameter of type 'string'.

Maybe, for small projects (or small functions like ours) we don’t really see too much benefit.

In this case, we know that we need to pass a string, so we won’t pass a number to the function. But when the codebase grows or you have many people adding code and more complexity, it’s clear to me that a type system can help us a lot to get errors in compile time before shipping code to production.

At first, we need all the learning curve to understand types and all the mental models, but after a while, you’ll be more used to type annotations and eventually become friends with the compiler. It would be a helper, not a yeller.

As we are learning about the basic difference between compile time and runtime, I think it’s great to differentiate types from values.

All the examples I’ll show here can be copied and run in the Typescript Playground to understand the compiler and the result of the compilation process (aka the “Javascript”).

In Typescript, we have two different universes: the value and the type spaces. The type space is where types are defined and used to enable the compiler to do all the great magic. And the value space is the values in our programs like variables, constants, functions, value literals, and things that we have in runtime.

It’s good to have an understanding of this concept because in Typescript we can’t use type checking in runtime. It has a very clear separation between type checking and the compilation process.

Typescript has the process of type checking the source code types and sees if everything is correct and consistent. And then it can compile to Javascript.

As these two parts are separate, we can’t use type checking in runtime. Only in “compile time”. If you try to use a type as a value, it will throw an error: only refers to a type, but is being used as a value here.

Let’s see examples of this idea.

Imagine we want to write a function called purchase where we receive a payment method and based on this method, we want to do some action. We have a credit card and a debit card. Let’s define them here:

type CreditCard = {
  number: number;
  cardholder: string;
  expirationDate: Date;
  secutiryCode: number;
};

type DebitCard = {
  number: number;
  cardholder: string;
  expirationDate: Date;
  secutiryCode: number;
};

type PaymentMethod = CreditCard | DebitCard;

These types are in the Type space, so it only works in compile time. After type checking this function, the compiler removes all the types.

If you add these types in the Typescript Playground, the output will be only a strict definition "use strict";.

The idea here is to really understand that the types live in the Type space and will not be available in the runtime. So in our function, it won’t be possible to do this:

const purchase = (paymentMethod: PaymentMethod) => {
  if (paymentMethod instanceof CreditCard) {
    // purchase with credit card
  } else {
    // purchase with debit card
  }
}

In the compiler it throws an error: 'CreditCard' only refers to a type, but is being used as a value here..

The compiler knows the difference between the two spaces and that the type CreditCard lives in the Type space.

The playground is a very cool tool to see the output of your Typescript code. If you create a new credit card object like this:

const creditCard: CreditCard = {
  number: 2093,
  cardholder: 'TK',
  expirationDate: new Date(),
  secutiryCode: 101
};

The compiler will type check it and do all the magic and then it transpiles the Typescript code to Javascript. And we have this:

const creditCard = {
    number: 2093,
    cardholder: 'TK',
    expirationDate: new Date(,
    secutiryCode: 101
};

The same object, but now only with the value and without the type.

#typescript #javascript #developer

What is GEEK

Buddha Community

TypeScript Types Explained – A Mental Model to Help You Think in Types
Armando  Bruen

Armando Bruen

1596508080

TypeScript Types Explained — A Mental Model to Help You Think in Types

One day I came across a tweet from Lari Mazza that says

“Can I make a suggestion? Types are hard to understand when you’ve only worked with JS in your life and suddenly have to learn TypeScript”

As a software engineer that learned Python, Ruby, Javascript, and Clojure first, when I tried C++, it was a horror movie. I couldn’t do much, so counterproductive, and frustrating. Maybe because I was doing everything wrong and I didn’t understand types the right way.

But even though I had so many problems, I could implement a bunch of algorithms and data structures.

Now I’m using more and more Typescript in my day-to-today job and my side projects, I feel I’m more prepared to confront types. Actually, not confront, but use them in my favor.

This post is my attempt to help developers think more in types and understand this mental model.

JavaScript types

If you’re here, you probably heard that Typescript is a superset of Javascript. If not, great, you just learned something new today. YAY!

Typescript is a superset because any Javascript code is valid in Typescript, syntactically speaking. It may or may not compile depending on the Typescript compiler configuration. But in terms of syntax, it works just fine. This is why you can migrate Javascript to Typescript progressively by just replacing the .js extension with the .ts. Everything will be without type declarations (the any type), but that’s another story.

Also, if you code in Javascript — or any other programming language — you probably think in types:

  • “Hm, it is a list of integers, so I’ll need to filter only the even numbers and return a new list”
  • “This is an object, but I just need to get this string value from the property X”
  • “This function receives two parameters. Both A and B are integers and I want to sum them”

Yeah, you got the idea. We think in types. But they are just in our heads. We constantly think about them because we need to know how to handle, parse, or modify data. We need to know which methods we are allowed to use in this object type.

To give a more concrete example, imagine you want to sum the price of all products. A product object looks like this:

const product = {
  title: 'Some product',
  price: 100.00,
};

But now with a list of products:

const products = [
  {
    title: 'Product 1',
    price: 100.00,
  },
  {
    title: 'Product 2',
    price: 25.00,
  },
  {
    title: 'Product 3',
    price: 300.00,
  }
];

Ok! Now we want a function to sum all the products prices.

function sumAllPrices(products) {
  return products.reduce((sum, product) => sum + product.price, 0);
};

sumAllPrices(products); // 425

Just receive the products as the argument and reduce all product prices. Javascript works just fine. But while building this function you start to think about the data and how to handle it properly.

The first part: products as an argument. Here you just think: “well, we’re receiving a list of some objects”. Yeah, in our heads the products are a list. This is why we can think of using the reduce method. It is a method from the Array prototype.

Then we can think about the object in detail. We know that the product object has a price property. And this property is a number. This is why we can do product.price and sum with the accumulator.

Recapping:

  • products is a list of objects.
  • As a list, we can use the reduce method, as this method a member of the Array prototype.
  • The produce object has some properties. One of them is the price, which is a number.
  • As a number property, we can use it to sum with the reduce accumulator.
  • We wanted to return a number, the sum of all product prices.

We are always thinking of data types, we just need to add the type annotations to make it more explicit and ask the compiler for help. Our memory is limited and the compilers are here to help us, humans.

The type system will not only make our data more consistent, but it can also provide autocompletion for data types. It knows the types, so it can show the members for the data. We will take a look at this idea later. Here I just wanted to show that we think in types in our heads.

#typescript #web-development #javascript #programming #software-development

Joshua Yates

Joshua Yates

1595389748

TypeScript Types Explained – A Mental Model to Help You Think in Types

One day I came across this tweet from Lari Mazza:

As a software engineer who learned Python, Ruby, Javascript, and Clojure first, when I tried C++ it was a horror movie. I couldn’t do much, and it was so counterproductive and frustrating. Maybe because I was doing everything wrong and I didn’t understand types the right way.

But even though I had so many problems, I could implement a bunch of algorithms and data structures.

Now that I’m using more and more Typescript in my day-to-day job and my side projects, I feel I’m more prepared to confront types. Actually, not confront, but use them in my favor.

This post is my attempt to help developers think more in types and understand this mental model.

Thinking in JavaScript types

If you’re here, you’ve probably heard that Typescript is a superset of Javascript. If not, great, you just learned something new today. YAY!

Typescript is a superset because any Javascript code is valid in Typescript, syntactically speaking. It may or may not compile depending on the Typescript compiler configuration. But in terms of syntax, it works just fine.

This is why you can migrate Javascript to Typescript progressively by just replacing the .js extension with the .ts. Everything will be without type declarations (the any type), but that’s another story.

Also, if you code in Javascript - or any other programming language - you probably think in types:

  • “Hm, it is a list of integers, so I’ll need to filter only the even numbers and return a new list”
  • “This is an object, but I just need to get this string value from the property X”
  • “This function receives two parameters. Both A and B are integers and I want to sum them”

Yeah, you get the idea. We think in types. But they are just in our heads. We constantly think about them because we need to know how to handle, parse, or modify data. We need to know which methods we are allowed to use in this object type.

To give a more concrete example, imagine you want to sum the price of all products. A product object looks like this:

const product = {
  title: 'Some product',
  price: 100.00,
};

But now with a list of products:

const products = [
  {
    title: 'Product 1',
    price: 100.00,
  },
  {
    title: 'Product 2',
    price: 25.00,
  },
  {
    title: 'Product 3',
    price: 300.00,
  }
];

Ok! Now we want a function to sum all the products prices.

function sumAllPrices(products) {
  return products.reduce((sum, product) => sum + product.price, 0);
};

sumAllPrices(products); // 425

Just receive the products as the argument and reduce all product prices. Javascript works just fine. But while building this function you start to think about the data and how to handle it properly.

The first part: products as an argument. Here you just think: “well, we’re receiving a list of some objects”. Yeah, in our heads the products are a list. This is why we can think of using the reduce method. It is a method from the Array prototype.

Then we can think about the object in detail. We know that the product object has a price property. And this property is a number. This is why we can do product.price and sum with the accumulator.

Recapping:

  • products is a list of objects.
  • As a list, we can use the reduce method, as this method is a member of the Array prototype.
  • The produce object has some properties. One of them is the price, which is a number.
  • As a number property, we can use it to sum with the reduce accumulator.
  • We wanted to return a number, the sum of all products prices.

We are always thinking of data types, we just need to add the type annotations to make it more explicit and ask the compiler for help. Our memory is limited and the compilers are here to help us, humans.

The type system will not only make our data more consistent, but it can also provide autocompletion for data types. It knows the types, so it can show the members for the data. We will take a look at this idea later. Here I just wanted to show that we think in types in our heads.

Simples Types & Simple Uses

So we are ready to use some strongly typed programming languages like Typescript. We simply need to explicitly add type annotations to our data structures. It’s simple, right?

But sometimes it’s not that easy (usually it’s not easy when you come from dynamically typed languages. You feel unproductive. It feels like a battle against types). The idea here is to make this learning curve smoother and more fun.

Here we will see many examples of how to use types in Typescript. We’ll start with easy and silly examples and progressively make it more complex while designing the mental model to think in types.

As in Javascript, Typescript also has basic data types like number, string, boolean, null, etc. You can find all the basic data types in the Typescript Docs.

With these units of data, we can make our programs more useful. To be more practical, let’s get a simple example. A sum function.

How does it work in Javascript?

function sum(a, b) {
  return a + b;
}

Everything ok? Good.

Now let’s use it:

sum(1, 2); // 3
sum(2, 2); // 4
sum(0, 'string'); // '0string'   WTF!

The first two calls are what we expect to happen in our system. But Javascript is very flexible, it lets us provide any value to this function.

The last call is bizarre. We can call with a string, but it will return an unexpected result. It doesn’t break in development, but it will result in strange behavior in runtime.

What do we want? We want to add some constraints to the function. It will only be able to receive numbers. That way, we narrow the possibility of having unexpected behaviors. And the function return type is also a number.

function sum(a: number, b: number): number {
  return a + b;
}

Great! It was very simple. Let’s call again.

sum(1, 2); // 3
sum(2, 2); // 4
sum(0, 'string'); // Argument of type '"string"' is not assignable to parameter of type 'number'.

As we type annotate our function, we provide information to the compiler to see if everything is correct. It will follow the constraints we added to the function.

So the first two calls are the same as in Javascript. It will return the correct calculation. But in the last one we have an error in compile time. This is important. The error now happens in compile time and prevents us from shipping incorrect code to production. It says that the string type is not part of the set of values in the number type universe.

For basic types, we just need to add a colon followed by the type definition.

const isTypescript: boolean = true;
const age: number = 24;
const username: string = 'tk';

Now let’s increase the challenge. Remember the product object code we wrote in Javascript? Let’s implement it again, but now with the Typescript mindset.

Just to remember what we are talking about:

const product = {
  title: 'Some product',
  price: 100.00,
};

This is the product value. It has a title as string and the price as number. For now, this is what we need to know.

The object type would be something like this:

{ title: string, price: number }

And we use this type to annotate our function:

const product: { title: string, price: number } = {
  title: 'Some product',
  price: 100.00,
};

With this type, the compiler will know how to handle inconsistent data:

const wrongProduct: { title: string, price: number } = {
  title: 100.00, // Type 'number' is not assignable to type 'string'.
  price: 'Some product', // Type 'string' is not assignable to type 'number'.
};

Here it breaks down into two different properties:

  • The title is a string and should not receive a number.
  • The price is a number and should not receive a string.

The compiler helps us to catch type errors like that.

We could improve this type annotation by using a concept called Type Aliases. It’s a way to create a new name for a specific type.

In our case, the product type could be:

type Product = {
  title: string;
  price: number;
};

const product: Product = {
  title: 'Some product',
  price: 100.00,
};

It’s better to visualize the type, add semantics, and maybe reuse in our system.

Now that we have this product type, we can use it to type the products list. The syntax looks like this: MyType[]. In our case, Product[].

const products: Product[] = [
  {
    title: 'Product 1',
    price: 100.00,
  },
  {
    title: 'Product 2',
    price: 25.00,
  },
  {
    title: 'Product 3',
    price: 300.00,
  }
];

Now the function sumAllPrices. It will receive the product and return a number, the sum of all product prices.

function sumAllPrices(products: Product[]): number {
  return products.reduce((sum, product) => sum + product.price, 0);
};

This is very interesting. As we typed the product, when we write product., it will show the possible properties we can use. In the product type case, it will show the properties price and title.

sumAllPrices(products); // 425
sumAllPrices([]); // 0
sumAllPrices([{ title: 'Test', willFail: true }]); // Type '{ title: string; willFail: true; }' is not assignable to type 'Product'.

Passing the products will result in the value 425. An empty list will result in the value 0. And if we pass an object with a different structure - Typescript has a structural type system and we will dig deep into this topic later - the compiler will throw a type error telling that the structure is not part of the Product type.

Structural Typing

Structural typing is a type of type compatibility. It’s a way to understand the compatibility between types based on its structure: features, members, properties. Some languages have type compatibility based on the names of the types, and it’s called nominal typing.

For example, in Java, even if different types have the same structure, it will throw a compile error because we are using a different type to instantiate and define a new instance.

class Person {
  String name;
}

class Client {
  String name;
}

Client c = new Person();  // compiler throws an error
Client c = new Client();  // OK!

In nominal type systems, the relevant part of a type is the name, not the structure.

Typescript, on another hand, verifies the structural compatibility to allow or not specific data. Its type system is based on structural typing.

The same code implementation that crashes in Java, would work in Typescript.

class Person {
  name: string;
}

class Client {
  name: string;
}

const c1: Client = new Person(); // OK!
const c2: Client = new Client(); // OK!

We want to use the Client type, and it has the property name, to point to the Person type. It also has the property type. So Typescript will understand that both types have the same shape.

But it is not only about classes, but it works for any other “object”.

const c3: Client = {
  name: 'TK'
};

This code compiles too because we have the same structure here. The typescript type system doesn’t care about if it is a class, or an object literal if it has the same members, it will be flexible and compile.

But now we will add a third type: the Customer.

class Customer {
  name: string;
  age: number;
};

It not only has the name property, but also the age. What would happen if we instantiate a Client instance in a constant of type Customer?

const c4: Customer = new Client();

The compiler will not accept that. We want to use the Customer, that has name and age. But we are instantiating the Client that has only the name property. So it doesn’t have the same shape. It will cause an error:

Property 'age' is missing in type 'Client' but required in type 'Customer'.

The other way around would work because we want Client, and Customer has all the properties (name) from Client.

const c5: Client = new Customer();

It works fine!

We can go on for enums, object literals, and any other type, but the idea here is to understand that the structure of the type is the relevant part.

Runtime and Compile time

This is a much more complex topic in programming language theory, but I wanted to give some examples to distinguish runtime from compile time.

Basically, the runtime is the execution time of a program. Imagine your backend receiving data from a frontend form page, handling this data, and saving it. Or when your frontend is requesting data from a server to render a list of Pokemons products.

Compile time is basically when the compiler is executing operations in the source code to satisfy the programming language’s requirements. It can include type checking as an operation, for example.

Compile time errors in Typescript, for example, are very related to the code that we wrote before:

  • When the type is missing property: Property 'age' is missing in type 'Client' but required in type 'Customer'.
  • When the type doesn’t match: Type '{ title: string; willFail: true; }' is not assignable to type 'Product'.

Let’s see some examples to have a better understanding.

I want to write a function to get the index of a part of the passed programming language.

function getIndexOf(language, part) {
  return language.indexOf(part);
}

It receives the language and the part that we will look for to get the index.

getIndexOf('Typescript', 'script'); // 4
getIndexOf(42, 'script'); // Uncaught TypeError: language.indexOf is not a function at getIndexOf

When passing a string, it works fine. But passing a number, we got a runtime error Uncaught TypeError. Because a number doesn’t have an indexOf function, so we can’t really use it.

But if we give type information to the compiler, in compile time, it will throw an error before running the code.

function getIndexOf(language: string, part: string): number {
  return language.indexOf(part);
}

Now our program knows that it will need to receive two strings and return a number. The compiler can use this information to throw errors when we get a type error… before runtime.

getIndexOf('Typescript', 'script'); // 4
getIndexOf(42, 'script'); // Argument of type '42' is not assignable to parameter of type 'string'.

Maybe, for small projects (or small functions like ours) we don’t really see too much benefit.

In this case, we know that we need to pass a string, so we won’t pass a number to the function. But when the codebase grows or you have many people adding code and more complexity, it’s clear to me that a type system can help us a lot to get errors in compile time before shipping code to production.

At first, we need all the learning curve to understand types and all the mental models, but after a while, you’ll be more used to type annotations and eventually become friends with the compiler. It would be a helper, not a yeller.

As we are learning about the basic difference between compile time and runtime, I think it’s great to differentiate types from values.

All the examples I’ll show here can be copied and run in the Typescript Playground to understand the compiler and the result of the compilation process (aka the “Javascript”).

In Typescript, we have two different universes: the value and the type spaces. The type space is where types are defined and used to enable the compiler to do all the great magic. And the value space is the values in our programs like variables, constants, functions, value literals, and things that we have in runtime.

It’s good to have an understanding of this concept because in Typescript we can’t use type checking in runtime. It has a very clear separation between type checking and the compilation process.

Typescript has the process of type checking the source code types and sees if everything is correct and consistent. And then it can compile to Javascript.

As these two parts are separate, we can’t use type checking in runtime. Only in “compile time”. If you try to use a type as a value, it will throw an error: only refers to a type, but is being used as a value here.

Let’s see examples of this idea.

Imagine we want to write a function called purchase where we receive a payment method and based on this method, we want to do some action. We have a credit card and a debit card. Let’s define them here:

type CreditCard = {
  number: number;
  cardholder: string;
  expirationDate: Date;
  secutiryCode: number;
};

type DebitCard = {
  number: number;
  cardholder: string;
  expirationDate: Date;
  secutiryCode: number;
};

type PaymentMethod = CreditCard | DebitCard;

These types are in the Type space, so it only works in compile time. After type checking this function, the compiler removes all the types.

If you add these types in the Typescript Playground, the output will be only a strict definition "use strict";.

The idea here is to really understand that the types live in the Type space and will not be available in the runtime. So in our function, it won’t be possible to do this:

const purchase = (paymentMethod: PaymentMethod) => {
  if (paymentMethod instanceof CreditCard) {
    // purchase with credit card
  } else {
    // purchase with debit card
  }
}

In the compiler it throws an error: 'CreditCard' only refers to a type, but is being used as a value here..

The compiler knows the difference between the two spaces and that the type CreditCard lives in the Type space.

The playground is a very cool tool to see the output of your Typescript code. If you create a new credit card object like this:

const creditCard: CreditCard = {
  number: 2093,
  cardholder: 'TK',
  expirationDate: new Date(),
  secutiryCode: 101
};

The compiler will type check it and do all the magic and then it transpiles the Typescript code to Javascript. And we have this:

const creditCard = {
    number: 2093,
    cardholder: 'TK',
    expirationDate: new Date(,
    secutiryCode: 101
};

The same object, but now only with the value and without the type.

#typescript #javascript #developer

The Definitive Guide to TypeScript & Possibly The Best TypeScript Book

TypeScript Deep Dive

I've been looking at the issues that turn up commonly when people start using TypeScript. This is based on the lessons from Stack Overflow / DefinitelyTyped and general engagement with the TypeScript community. You can follow for updates and don't forget to ★ on GitHub 🌹

Reviews

  • Thanks for the wonderful book. Learned a lot from it. (link)
  • Its probably the Best TypeScript book out there. Good Job (link)
  • Love how precise and clear the examples and explanations are! (link)
  • For the low, low price of free, you get pages of pure awesomeness. Chock full of source code examples and clear, concise explanations, TypeScript Deep Dive will help you learn TypeScript development. (link)
  • Just a big thank you! Best TypeScript 2 detailed explanation! (link)
  • This gitbook got my project going pronto. Fluent easy read 5 stars. (link)
  • I recommend the online #typescript book by @basarat you'll love it.(link)
  • I've always found this by @basarat really helpful. (link)
  • We must highlight TypeScript Deep Dive, an open source book.(link)
  • Great online resource for learning. (link)
  • Thank you for putting this book together, and for all your hard work within the TypeScript community. (link)
  • TypeScript Deep Dive is one of the best technical texts I've read in a while. (link)
  • Thanks @basarat for the TypeScript Deep Dive Book. Help me a lot with my first TypeScript project. (link)
  • Thanks to @basarat for this great #typescript learning resource. (link)
  • Guyz excellent book on Typescript(@typescriptlang) by @basarat (link)
  • Leaning on the legendary @basarat's "TypeScript Deep Dive" book heavily at the moment (link)
  • numTimesPointedPeopleToBasaratsTypeScriptBook++; (link)
  • A book not only for typescript, a good one for deeper JavaScript knowledge as well. link
  • In my new job, we're using @typescriptlang, which I am new to. This is insanely helpful huge thanks, @basarat! link
  • Thank you for writing TypeScript Deep Dive. I have learned so much. link
  • Loving @basarat's @typescriptlang online book basarat.gitbooks.io/typescript/# loaded with great recipes! link
  • Microsoft doc is great already, but if want to "dig deeper" into TypeScript I find this book of great value link
  • Thanks, this is a great book 🤓🤓 link
  • Deep dive to typescript is awesome in so many levels. i find it very insightful. Thanks link
  • @basarat's intro to @typescriptlang is still one of the best going (if not THE best) link
  •  
  • This is sweet! So many #typescript goodies! link

Get Started

If you are here to read the book online get started.

Translations

Book is completely free so you can copy paste whatever you want without requiring permission. If you have a translation you want me to link here. Send a PR.

Other Options

You can also download one of the Epub, Mobi, or PDF formats from the actions tab by clicking on the latest build run. You will find the files in the artifacts section.

Special Thanks

All the amazing contributors 🌹

Share

Share URL: https://basarat.gitbook.io/typescript/

Author: Basarat
Source Code: https://github.com/basarat/typescript-book/ 
License: View license

#typescript #opensource 

Wiyada Yawai

1607523900

How To Create Tabs in Less Than 12 Minutes Using HTML CSS

In this video, We have created a Tab design in HTML and CSS without using JavaScript. I have also provided HTML and CSS code on my website, you can visit my website by clicking given link. 

Subscribe: https://www.youtube.com/@CodingLabYT/featured 

Source Code :

HTML :

<!DOCTYPE html>
<html lang="en" dir="ltr">
  <head>
    <meta charset="UTF-8">
    <!--<title> CSS Vertical Tabs </title>-->
    <link rel="stylesheet" href="style.css">
    <!-- Fontawesome CDN Link -->
    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.2/css/all.min.css"/>
     <meta name="viewport" content="width=device-width, initial-scale=1.0">
   </head>
<body>
  <div class="container">
    <div class="topic">CSS Vertical Tabs.</div>
    <div class="content">
      <input type="radio" name="slider" checked id="home">
      <input type="radio" name="slider" id="blog">
      <input type="radio" name="slider" id="help">
      <input type="radio" name="slider" id="code">
      <input type="radio" name="slider" id="about">
      <div class="list">
        <label for="home" class="home">
        <i class="fas fa-home"></i>
        <span class="title">Home</span>
      </label>
      <label for="blog" class="blog">
        <span class="icon"><i class="fas fa-blog"></i></span>
        <span class="title">Blog</span>
      </label>
      <label for="help" class="help">
        <span class="icon"><i class="far fa-envelope"></i></span>
        <span class="title">Help</span>
      </label>
      <label for="code" class="code">
        <span class="icon"><i class="fas fa-code"></i></span>
        <span class="title">Code</span>
      </label>
      <label for="about" class="about">
        <span class="icon"><i class="far fa-user"></i></span>
        <span class="title">About</span>
      </label>
      <div class="slider"></div>
    </div>
      <div class="text-content">
        <div class="home text">
          <div class="title">Home Content</div>
          <p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Quasi excepturi ducimus sequi dignissimos expedita tempore omnis quos cum, possimus, aspernatur esse nihil commodi est maiores dolorum rem iusto atque, beatae voluptas sit eligendi architecto dolorem temporibus. Non magnam ipsam, voluptas quasi nam dicta ut. Ad corrupti aliquid obcaecati alias, nemo veritatis porro nisi eius sequi dignissimos ea repellendus quibusdam minima ipsum animi quae, libero quisquam a! Laudantium iste est sapiente, ullam itaque odio iure laborum voluptatem quaerat tempore doloremque quam modi, atque minima enim saepe! Dolorem rerum minima incidunt, officia!</p>
        </div>
        <div class="blog text">
          <div class="title">Blog Content</div>
          <p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Alias tempora, unde reprehenderit incidunt excepturi blanditiis ullam dignissimos provident quam? Fugit, enim! Architecto ad officiis dignissimos ex quae iusto amet pariatur, ea eius aut velit, tempora magnam hic autem maiores unde corrupti tenetur delectus! Voluptatum praesentium labore consectetur ea qui illum illo distinctio, sunt, ipsam rerum optio quibusdam cum a? Aut facilis non fuga molestiae voluptatem omnis reprehenderit, dignissimos commodi repellat sapiente natus ipsam, ipsa distinctio. Ducimus repudiandae fuga aliquid, numquam.</p>
        </div>
        <div class="help text">
          <div class="title">Help Content</div>
          <p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Maiores error neque, officia excepturi dolores quis dolor, architecto iusto deleniti a soluta nostrum. Fuga reiciendis beatae, dicta voluptatem, vitae eligendi maxime accusamus. Amet totam aut odio velit cumque autem neque sequi provident mollitia, nisi sunt maiores facilis debitis in officiis asperiores saepe quo soluta laudantium ad non quisquam! Repellendus culpa necessitatibus aliquam quod mollitia perspiciatis ducimus doloribus perferendis autem, omnis, impedit, veniam qui dolorem? Ipsam nihil assumenda, sit ratione blanditiis eius aliquam libero iusto, dolorum aut perferendis modi laboriosam sint dolor.</p>
        </div>
        <div class="code text">
          <div class="title">Code Content</div>
          <p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Tempore magnam vitae inventore blanditiis nam tenetur voluptates doloribus error atque reprehenderit, necessitatibus minima incidunt a eius corrupti placeat, quasi similique deserunt, harum? Quia ut impedit ab earum expedita soluta repellat perferendis hic tempora inventore, accusantium porro consequuntur quisquam et assumenda distinctio dignissimos doloremque enim nemo delectus deserunt! Ullam perspiciatis quae aliquid animi quam amet deleniti, at dolorum tenetur, tempore laborum.</p>
        </div>
        <div class="about text">
          <div class="title">About Content</div>
          <p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Necessitatibus incidunt possimus quas ad, sit nam veniam illo ullam sapiente, aspernatur fugiat atque. Laboriosam libero voluptatum molestiae veniam earum quisquam, laudantium aperiam, eligendi dicta animi maxime sunt non nisi, ex, ipsa! Soluta ex, quibusdam voluptatem distinctio asperiores recusandae veritatis optio dolorem illo nesciunt quos ullam, dicta numquam ipsam cumque sed. Blanditiis omnis placeat, enim sit dicta eligendi voluptatibus laborum consectetur repudiandae tempora numquam molestiae rerum mollitia nemo. Velit perspiciatis, nesciunt, quo illo quas error debitis molestiae et sapiente neque tempore natus?</p>
        </div>
      </div>
    </div>
  </div>

</body>
</html>

CSS :

@import url('https://fonts.googleapis.com/css2?family=Poppins:wght@200;300;400;500;600;700&display=swap');
*{
  margin: 0;
  padding: 0;
  box-sizing: border-box;
  font-family: 'Poppins', sans-serif;
}
body{
  height: 100vh;
  display: flex;
  align-items: center;
  justify-content: center;
  background: #dad3f8;
}
::selection{
  background: #6d50e2;
  color: #fff;
}
.container{
  max-width: 950px;
  width: 100%;
  padding: 40px 50px  40px  40px;
  background: #fff;
  margin: 0 20px;
  border-radius: 12px;
  box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2);
}
.container .topic{
  font-size: 30px;
  font-weight: 500;
  margin-bottom: 20px;
}
.content{
  display: flex;
  align-items: center;
  justify-content: space-between;
}
.content .list{
  display: flex;
  flex-direction: column;
  width: 20%;
  margin-right: 50px;
  position: relative;
}
.content .list label{
  height: 60px;
  font-size: 22px;
  font-weight: 500;
  line-height: 60px;
  cursor: pointer;
  padding-left: 25px;
  transition: all 0.5s ease;
  color: #333;
  z-index: 12;
}
#home:checked ~ .list label.home,
#blog:checked ~ .list label.blog,
#help:checked ~ .list label.help,
#code:checked ~ .list label.code,
#about:checked ~ .list label.about{
  color: #fff;
}
.content .list label:hover{
  color: #6d50e2;
}
.content .slider{
  position: absolute;
  left: 0;
  top: 0;
  height: 60px;
  width: 100%;
  border-radius: 12px;
  background: #6d50e2;
  transition: all 0.4s ease;
}
#home:checked ~ .list .slider{
  top: 0;
}
#blog:checked ~ .list .slider{
  top: 60px;
}
#help:checked ~ .list .slider{
  top: 120px;
}
#code:checked ~ .list .slider{
  top: 180px;
}
#about:checked ~ .list .slider{
  top: 240px;
}
.content .text-content{
  width: 80%;
  height: 100%;
}
.content .text{
  display: none;
}
.content .text .title{
  font-size: 25px;
  margin-bottom: 10px;
  font-weight: 500;
}
.content .text p{
  text-align: justify;
}
.content .text-content .home{
  display: block;
}
#home:checked ~ .text-content .home,
#blog:checked ~ .text-content .blog,
#help:checked ~ .text-content .help,
#code:checked ~ .text-content .code,
#about:checked ~ .text-content .about{
  display: block;
}
#blog:checked ~ .text-content .home,
#help:checked ~ .text-content .home,
#code:checked ~ .text-content .home,
#about:checked ~ .text-content .home{
  display: none;
}
.content input{
  display: none;
}

Download Code Files

#javascript #html #css

Verdie  Murray

Verdie Murray

1636240140

What Is The Main Difference Of TYPES Vs INTERFACES in TypeScript

TypeScript has two ways of declaring structures of your objects in the form of  #types (type aliases) and #interfaces.

In this lesson we will look at the technical differences between these two, when you should use which, along with real world #TypeScript code analysis, and community thoughts

#typescript