- Now, as I mentioned in the last video,
sometimes you run into a library
that doesn't have any types yet
and you may need to add your own types.
In this video, I'm gonna show you how you can do that
as well as a few other tricks
related to this declaration file.
So what I have here is I have lodash being installed
but I don't have the types for lodash installed,
and I'm just going to pretend like these types don't exist,
that the only thing in this lodash library
is this times function
and that it should take a number
and return to us an array of numbers as the result.
That's what I'm assuming should happen for this function
but, obviously, there's no types for it,
so I don't get any of that type safety.
In order to write the types for either a library
or the built-in types that are built into JavaScript,
you need to use a declaration file,
and we've already looked at this a little bit.
For example, if I just like look at the document object,
you can see up here the file name is lib.dom.d.ts.
Anytime you see a .d.ts file,
that is considered a declaration file,
and this is a file that's not actually
having any code in it,
it has only types in it,
and it's specifically used to add types to libraries
as well to built-in types.
You'll see here, we already have this vite-env.d.ts,
which is doing some tricky stuff
to add specific Vite types in,
so when I type in like import.meta, for example,
I'm getting specific Vite-related types
from all of that information.
The other really important thing to understand
about these .d.ts files
is you don't need to worry about importing them
because all .d files are automatically inferred
and imported everywhere that you use your code,
so you don't have to worry about manually importing them
'cause it's already handled for you.
So if you want to add types to a library
that those types do not exist for,
you need to create a .d.ts file.
It doesn't matter what you call it.
Generally, if you're adding types to a library,
it makes sense to give it the same name
as the library you're trying to override.
So in our case, lodash.d.ts.
Then what we need to do, this is a really important step,
is you need to write that you want to declare a module
and the name of this module, which is a string,
must directly match the library name you're overriding.
So in our case, we are declaring a module for lodash
right here,
and then we'll open that up like that.
And now when we've done that,
we've at least gone a step further.
Our error has moved
because now we have types for this library,
but it's saying that we don't have types
for this times method yet.
So inside of this module, we can declare whatever we want.
You know, we can declare types,
we declare interfaces,
in our case, we're gonna declare a function called times.
This function is going to take in a number
with the type of number,
and it's going to return a number array.
Just by saving that,
you'll now see that all of our errors are gone,
and if we actually hover over this function,
you can see it's a function that takes in a number
and returns to us a number array.
Now if I changed it
to say that this is actually a string instead,
you'll see I get an error over here
because this should be a string.
So it's properly updating all that information.
So if you need to type out a library,
the way to do it is to declare a module
with the name of your library
and then write all of your types inside of that module.
Now, luckily for the most part,
you're probably not going to need to do this,
but if you do, sometimes writing out these types
can be quite difficult
because writing out the types for a library
can sometimes be fairly advanced.
But hopefully, this isn't something that you need to do
because like I've said,
most libraries are already typed for you.
One thing that you will probably have to do at some point
that relates to declaration files, though,
is overriding the global values that are available for you.
For example,
let's say that I wanted to add a method to console
and I wanted to call it superLog.
This is a terrible idea.
You should never actually do something like this.
Let's just say, for our purposes,
this is something that I want to do.
Well, what I would need to do
is create a declaration file for this.
So you can call it whatever you want,
again, it doesn't matter.
We'll just call it globals.d.ts.
And here, instead of declaring a module,
what I wanna do is I wanna declare global.
And this is just saying,
this is going to be something that is globally available.
And since the console object
is something that's globally available,
I want to declare that as a global thing.
So now how do I actually get to that console object itself?
Well, what I need to do is I need to look at the console
to see how I override it.
So I can come into this console
and I can see that it has this type right here of console.
So what I need to do is if I look at this,
you can see this is an interface called the console.
So I just wanna copy this exactly.
I wanna put that inside my globals here.
So I'm just saying I have an interface called console
and that directly matches this console right here.
And now I can add my own custom stuff into here
and it's gonna mesh the two of them together.
For example, I can create a superLog function
and this is just gonna be a function
that accepts no arguments and returns void.
Now, this will mesh the two of them together,
but you'll notice we're still getting an error over here
saying that superLog does not exist.
Now, the reason for that
is when you override globals like this,
you need to make sure you export something in your file
or it won't know what to do.
Sometimes you may have something to export
but if you have nothing to export,
just put an export with an empty object
and that tells TypeScript, "Hey, look at this file
and actually use it."
You don't need to do that when you're declaring a module,
but if you're not declaring a module or exporting anything,
you need to make sure you add that line in there.
Now, you can see this superLog works
and we actually get it typed perfectly.
And all of our other methods are still there,
but this superLog is a new method that we've just added.
Now, like I said, this is not something I would ever do.
It's a really bad idea to monkey patch into the library.
Essentially, that means add properties
to the existing JavaScript libraries.
But one thing that's really common
is you may be using like jQuery, for example,
where you need to say
that the dollar sign is a global variable,
or you may add your own global variables
that you want to be able to have typed.
What you can do instead is you could declare a variable
by saying declare var and then call it whatever you want.
So if we were doing like jQuery,
you know, you could call a dollar sign,
in our case, we'll just call this test
and we'll say that this is a number.
So now I'm saying that globally,
on my this object on the window,
I have a test variable that is a number.
So if I come into my code and I just write out test,
you'll notice that this is a number and it works just fine,
and it works just like, if I say window.test,
you can see it's right there.
That's essentially what the global object is
when you're working in the DOM.
And this is a fairly common use case
because you're probably working in some older code
that may have some global variables
or even just in general,
you may have some global variables that you want to type.
This is the way that you're going to want to do that.
Again, the file name doesn't matter.
As long as it has a .d.ts,
that's all TypeScript needs to know
to be able to say that this is a declaration file.
And again, you may make sure
you have this export at the bottom
just to make sure TypeScript actually reads this file.
Essentially, if you don't have that, it won't work
because it just doesn't look at this file at all.
So if you're running into errors where your code looks right
but it's not working,
it's most likely because you forgot to put
this export in there.