Check out a free preview of the full Intermediate TypeScript, v2 course:
The "Identifiers" Lesson is part of the full, Intermediate TypeScript, v2 course featured in this preview video. Here's what you'd learn in this lesson:

Mike explains how TypeScript allows for the creation of different importable and exportable things across module boundaries. The concept of namespaces and how multiple things can be stacked on top of each other in an identifier is also discussed in this segment.

Get Unlimited Access Now

Transcript from the "Identifiers" Lesson

[00:00:00]
>> The first topic we're gonna discuss today is a declaration merging. So, TypeScript and JavaScript, well, sorry, TypeScript lets us create different kinds of things that can be imported and exported across module boundaries. So, if you imagine I've got a situation like what I'm showing on the screen here, we have an interface called Fruit.

[00:00:27] We can create a banana that is a value of type Fruit, and we can see that fruits have a property on them called name, mass, and color. And we have name, mass and color here. We can see banana is a named thing with something associated with it. Fruit is a name thing with something associated with it.

[00:00:52] We're exporting both of these things. You can see on the tool tips here, const banana: Fruit, interface Fruit, great. So I'm gonna coin a term here, and let's call these importable, exportable things with a name. Let's call them identifiers. Internally, TypeScript calls these a ts.symbol. But JavaScript has a concept called symbols.

[00:01:19] So we're not gonna call them that, we're gonna call them identifiers. So let's change our situation a little bit. Let's introduce a function. So we've got a function called fruit. It takes an argument that's a string, and you can see that, depending on the string we pass in, it's going to return an instance of Fruit.

[00:01:51] So it's gonna return banana which already exists, right, that's that's coming from up here. So if we look at the function Fruit, it takes a string as an argument, it returns a fruit. It's a :fruit at the end, great. Let's look at our export statement again. So banana is as we left it.

[00:02:17] But look at Fruit, Fruit has two things with this little alias word before that. It has a function Fruit and it has the interface that was there when we started. What we're seeing here is something called declaration merging. Fruit is a single identifier, a single exportable or importable thing, that now has two things stacked on top of it.

[00:02:45] We can take this one step further. We're gonna add something called a namespace and I'll get into what a namespace is and when you might use it. It's actually not super important to remember it but it's useful when thinking about declaration merging. We're creating a namespace called Fruit.

[00:03:08] It's got a function on it, appears to have a function within it called createBanana. It invokes Fruit, and it's gonna get that banana instance returning. Let's go down and look at our export statement one more time. Look at that, we have three things stacked on top of each other.

[00:03:26] We have a function, we have an interface, and we have a namespace. A function is a value, right? We know we can create, you can use like const fruit equals and then put an arrow function. Functions are just values. You could pass a function into another function, anytime you use a callback, that's what you're doing.

[00:03:47] Interface is a type. We know its type. Namespace is kind of something else. I want you to think of it as like another value. It is a value, we'll prove this to ourselves with an evidence-based approach here. But it's special enough that TypeScript gives it its own slot on an identifier here.

[00:04:12] So, how do we tell what's on an identifier? LiWe see we've got three things stacked on top of each other, and short of just looking at the tooltip, we're gonna have to resort to that for one of these things. But how do we know what's on an identifier?

[00:04:26] So, there are a couple tests that we can perform and we're gonna go through them one by one here. So first, I'm gonna create a bunch of different things. This, clearly a value, right? This is like a variable. We're setting it equal to 4, that's a value. This very clearly as a type so I'm creating a type alias, it happens to be the empty object type here.

[00:04:49] The third thing we're creating is a namespace. I haven't really discussed namespaces but I'm just borrowing the syntax here. It says if we just took the namespace Fruit, renamed it and took everything inside of it out or we're just putting another variable in here. So those were our three things we're going to use as we perform tests.

[00:05:10] So we have tests for checking whether something within an identifier has a value on it. We have something for checking whether an identifier has a type on it. And then finally, there's no great way to differentiate between values and namespaces using some expression like this. So this one you sort of have to hover over it and look at the tool tip.

[00:05:33] And namespace can pass for a value in a lot of cases. So this is the one where I have to say, hover over the thing. There's no expression you can write that will only work if something is a namespace, the value stuff will work as well. So let's convince ourselves that these tests work by looking at some negative test cases.

[00:05:55] So here, we're trying to use a type in the value position, right, on the right hand side of a variable assignment. And it's saying it's a type, only refers to a type but it's being used as a value here that's very clear, right? It's saying there is no value on this identifier.

[00:06:13] Here is a namespace being used as a value. This is reinforcing the idea that it can be used in value space, meaning in places where values are the only things you can use. Here, we're trying to use a value as a type and it's telling you very clearly, this refers to a value but you're trying to use it as a type.

[00:06:35] This means there's no type on this identifier. And then finally, namespaces, it's the same test you perform as values, right? You can't use namespaces as a type either. You could use a type query, but remember, type queries, the whole point of those is to get the type of a value.

[00:06:54] Something like that and it would work. But this here, you could also think of this as proof that this is a value cuz if you did this, It's not gonna be happy here. Type of is another way you could test to see if something's a value. You can't say type of and then provide something without a value.

[00:07:17] Great, so we know these tests work.