Episode transcript for the podcast “Listen, Learn, and Code”. See podcast overview for more episodes and additional information.

Transcript

Hello and welcome to “Listen, Learn, and Code” - the podcast where you can learn coding while doing something else, like taking a shower, or working in the garden.

In this episode, we will begin our deep dive into the most important aspect of TypeScript, which is - of course - types. We will learn about the “string” data type, and how to use it in so-called “Type Annotations”. So, get ready, and let’s get started!

We already used our first data type in the previous episode. The “Hello World” greeting has the datatype string, and we enclosed it in double quotes to signal this to TypeScript. Just as in JavaScript, you can also use single quotes instead of double quotes - they both have the same meaning. Single quotes are handy when you embed JavaScript into HTML, because they don’t collide with the double quotes for the attribute values of HTML elements.

So let’s play a little bit with this “Hello World” example. First, we move the string into its own variable, with the following code:

let s = "Hello World";
console.log(s);

Note that I don’t mention obvious spaces or semicolons any longer.

At this point, TypeScript already knows that variable “s” holds a string. In other words, TypeScript figures out, or “infers” the data type of this variable. If you hover your mouse over the variable s, you will see that it has the type “string”.

In this example, inferring the data type is not a big deal because it’s enough to look at one single line of code. But when TypeScript compiles your code, it performs a complete analysis that can figure out the data types for much more complicated cases.

Now that TypeScript knows that your variable is a string, it makes sure that you only do things with it that are allowed for strings. For example, you can call string functions on it (such as toLowerCase), or you can assign another string value to it. But if you try to call some non-existing method on it (such as “foobar”), or if you try to assign a number to it, TypeScript will complain and report an error.

This type inference is nice because you can take an existing JavaScript program and, without changing it, compile it with TypeScript. Certain errors will already pop up at this point, without having to write any TypeScript-specific code.

Now let’s tell TypeScript explicitly that the variable s is a string:

let s: string = "Hello World";

So after the variable name (s), we write a colon, and then the name of the data type (string). This is called a “type annotation”. For those of you who already know Java this will look a bit unusual, because the data type comes after the variable name, and not before. Also, be careful to write “string” in lowercase characters, which refers to the primitive type. There is also a “String” type with an uppercase “S”, but you should not use this object type directly in TypeScript. As a Java programmer, you might say “But I want to invoke functions on the string, and I need the object type for that!” That’s true, and JavaScript will automatically wrap the primitive into an object for invoking the function. This wrapper object is only temporary helper, so it will be thrown away after the function invocation. That’s why you don’t have to use the object type “String” with an uppercase s. But on the other hand, if you use it explicitly in certain places, you might get problems in other places where primitives are expected. Long story short: Just use the primitive string type with lowercase “s”.

In simple examples like this, some people argue that explicitly writing down the data type is useless because it is easy to see anyway. I’ve introduced it here anyway because we will use the exact same syntax with colon also in other cases.

Now if we compile this program and take a look at the generated JavaScript code, we will see that there is no trace of the explictly provided “string” type. That’s because JavaScript wouldn’t know what to do with these types, and so they are removed by the TypeScript compiler to make JavaScript happy.

So we have seen how to declare the type for a variable, as in let s: string. Now what about functions? Let’s start with simple example without type annotations. The function in the following code receives a parameter named x, transforms it to upper case, and returns the result. Since uppercase words are usually perceived as screaming, the function is called “scream”. The code is this:

function scream(x) {
  return x.toUpperCase();
}

So if we send a nice “Hello World” greeting into this function, we will get a screamed, uppercase greeting in return.

Inside this function, TypeScript does not know that the parameter x is intended to be a string. This means that it doesn’t give you code completion inside the function. Also, it doesn’t warn you if you have a typo in the “toUpperCase” invocation, and it doesn’t warn you if give it a non-string input. The solution is to add an explicit type annotation for the parameter. This looks similar to what we did before, namely:

function scream(x: string) { 
    // and the rest remains as before

So again, we write down the variable name x, followed by a colon and the data type (string). This way, we have provided a type annotation for a function parameter. And with this information, TypeScript already infers that this function returns a string. We can also make the return type explicit by writing:

function scream(x: string): string { 
    // and the rest remains as before

In other words, we write a colon after the closing bracket of the parameter list, followed by the return type “string”. Explicit function return types make sense because they make the code easier to understand, and they help you to prevent errors. Suppose that you forget to write the brackets for the “toUpperCase” invocation, so you just write

return x.toUpperCase;

With this code, you don’t return a string, but the “toUpperCase” function itself, which is not what we wanted. With an explicit function return type, TypeScript will give you a warning for this.

So to sum up what we did in this episode:

  • We learned what type annotations are, and how to apply them to
    • variable declarations
    • function parameters, and
    • function return types
  • And we played a little bit with the “string” data type.

And that’s all for now. I hope you enjoyed this episode, and hear you next time on “Listen, Learn, and Code”.