I am currently learning, or at least trying to learn about, namespaces and modules in TypeScript. I have only one question: what the hell? Why would I ever declare a namespace or module instead of just putting data I need to share in a seperate file and just importing that? Is this just something from the past that refuses to die, or is there actually an advantage over putting data in a seperate file?
#Why would I want to use `namespace` or `module` over just putting data in seperate files?
150 messages · Page 1 of 1 (latest)
i'd say it's mostly a relic (typescript came into being before ES modules were fully specified, and even after they were specified it took a long time for them to be widely supported). some people like being able to group things within files, but i'd generally try to avoid that
use cases are kinda similar to this proposal: https://github.com/tc39/proposal-module-declarations
I am currently trying to understand a 300+ file codebase that uses them here and there and they just break my mind
conceptually they aren't too complicated; just think of them as an inlined file. what breaks your mind about them?
How you share them across files, and also why you even want to use them
you can export/import them just like an object/class. the only magical thing about them is that they can contain types as well as values
if you look at the emit they literally compile down to an object (albeit one created in a funky way for scoping reasons)
sure, that's how most modern abstractions can be described 😂
classes, functions, etc are all "code within code"
you can sorta analogize namespaces to classes with all-static methods. or just objects with unusual initialization syntax
that might be easier than the "file within a file" analogy
how is this allowed
declare module "*.replacements" {
const content: {
file: string;
filename: string;
};
export default content;
}
but this isnt
declare module "thisisamodule.ts" {
const thing: {
six: 6;
text: string;
};
export default thing;
}
oh that's a totally different thing
declare module is for declaring type definitions for javascript modules
javascript modules?
the things you import from, is all i mean
oh aha
so a type definition is just the javascript version of making a type?
oh wait I get it now
this question confuses me and even if i guess at what it means i don't get how it's related to what we were talking about. is there a typo?
the file extension has to be .d.ts in order for declare module to work?
no, im just stupid like this :)
ooooh
wait
I do
declare module "thisisamodule.ts" {
const thing: {
six: 6;
text: string;
};
export default thing;
}
``` in a `.d.ts` file so I can use types in `.js` files?
i don't think it has to be, but it generally should be
Deno certainly shut up when I changed it
pretty sure you can declare them in .ts files too (though i'd complain if i saw that in a pull request)
anyway yeah this sounds like you're getting it
but how do I use types in javascript, isnt that what typescript was invented for?
oh it might only be allowed in non-module (script) .ts files
you don't, but you do want to be able to interoperate with pre-existing javascript code from typescript
that's what this is for
whenever you see the keyword declare (not just declare module, but declare ANYTHING) it means "hey typescript compiler, i know there is going to be some existing code at runtime satisfying these types"
like all of the built-in stuff (Date, Math, etc) is defined via declare stuff
the d in d.ts is also short for "declaration", meaning the same thing
two questions
first
wait
is this related to the satisfy keyword I saw yesterday for the first time ever
not really
i mean they're related in that they are both doing things with types, but that's true for everything in typescript
you could say its in the name
okay then three questions
first
how do you tell the typescript compiler that some variable is satisfying a type in javascript (in typescript its trivial)
Second: how do I make a completely global variable / class myself?
third: then what is the satisfies keyword used for?
can you show me an example of what you have in mind here? (pseudocode is fine)
use a "script" file instead of a module and/or attach stuff to globalThis. but let's circle back to this after you get an answer to your first question
const thing = {
six: 6,
text: "hey hello there mister mkantor",
} // Hey hello there typescript compiler, I know this is a .js file but i would like to mention this satisfies a type you saw in the thing.d.ts file earlier
oooh right
nothing yet, just wanting to know in case I encounter it in the wild later on
wait how do I do it in typescript, my lsp doesn't say that thing is defined
you need to import thing. since it's a default export i think you can write import thing from "thisisamodule"
(but also you shouldn't write code like this except for interoperability with non-typescript code. just use normal typescript stuff otherwise)
oh right
I might, but others wont so I still have to know how it works
that is how I feel about this entire thing with namespaces and modules and the declare keyword
that's the right feeling IMO
so here's some history that might help avoid confusion:
- the
modulekeyword originally meant whatnamespacemeans today - since
modulemay end up being a valid JS keyword (as in the TC39 proposal i linked to above), typescript addednamespaceand deprecatedmodule(i think this meaning only became fully unsupported in the latest version of typescript) declare moduleis its own thing, still valid for what we've been discussing here
so basically if you see declare module it means "there's some JS code somewhere i am describing". if you see namespace it's what i originally was talking about (weird syntax for an object + types)
but IMO if you are just authoring your own typescript code you shouldn't use either declare module or namespace
what if I see declare namespace
declare generally means "i'm just talking about the type of a value i promise will exist when you go to run the code"
so it's like declare const x: string or declare class Foo {}, but for a namespace
I also saw typeof namespaceName today which made me really mad, like why would you ever need that
it's sorta the same idea as typeof ClassName. if you want to pass around the namespace itself as an object, that's how you talk about its type
you keep saying "a type of a value" but I can also just put regular data in a declare module?
similar to what now
I saw that, but why would you ever want that
the namespace is valid everywhere, its global data
not necessarily. it's a value like any other that can be in a module or a global script
wait let me grab the exampe
const x = { /* stuff */ } and namespace x { /* stuff */ } aren't much different at runtime
do you know about static vs instance properties? i can explain this with an example but want to make sure it'll make sense to you
static is persistant across all instaces of a class, instatic is not
function mapFactory(api: google.maps) {
return new api.Map();
}
Why would you pass api as a parameter, cant you just do:
function mapFactory() {
return new google.maps.api.Map();
}
google.maps appears to be a type, not a value, so new google.maps.api.Map() probably throws a runtime error
(unless there also happens to be a value of that name)
let me send the post where I based this on
but also maybe you want to allow more than once instance of the API object to exist at the same time ¯_(ツ)_/¯
this
last time I checked you cant have a class definition on a type
For unit testablity
☝️ that's alluding to "you want to allow more than once instance of the API object to exist at the same time"
oh damnit
but in any other case this would be unnecessary right? so I am still partially correct :)
okay but now the second questipn
how do I make namespaces global
my first-order snide-but-serious answer is: "don't" 😄
i can explain how if you're certain you really need to do that
but generally in modern javascript/typescript you should avoid global stuff
i am seeing that a namespace is accessed in a file without it importing it
said namespace is defined in a package
with declare namespace
do you know the difference between a "script" (sometimes called "ambient") and a "module"?
I do not
how long have you been doing web stuff? just wondering what i can gesture at to explain this stuff
like, have you written <script> tags yourself?
I have done almost exclusively discord bots and other stuff that does not involve frontend things in anyway
well except for svelte(kit), ubut that is a different story
barely
okay no worries
so typescript (under certain module settings) can treat a .ts file in one of two ways depending on what it contains: either as a "script" or a "module"
oh sorry phone call, be back in a bit
I published my own JSR package for backend routing, but i can count the amount of script tags I have made on my hands 😅
no problem
alright i'm back
maybe give this a read and then come back if you still have questions: https://www.typescriptlang.org/docs/handbook/modules/theory.html#scripts-and-modules-in-javascript
also worth reading https://www.typescriptlang.org/tsconfig/#moduleDetection; config options can affect this behavior
beyond what this says, the important bit to know is that all code in "script files" exists in the global scope, whereas code in "module files" is modularized (lol), meaning you need to explicitly import stuff
I am also back
holy hell thats way to much text for my adhd to read
ill try
omg typescripts biggest weakness is javascript
dude it's like 5 sentences (disregarding the blue box talking about ESM vs CJS, which is mostly irrelevant)
i'm not saying to read the whole page (though it does have lots of good nuggets/history), just that one section i linked to
thats exactly what im doing right now 😭
ok 7 sentences 😄
I wish someone made a new internet with a language that isn't bad. No matter how good your framework / wrapper language for web purposes is, the bottleneck will always be javascripts bad design.
people thought webassembly would be this. and maybe some day it will, but that day is not today
Some time ago a informatics (coding) teacher asked me and a bunch of other students to do a project together because we had coding as a hobby, and my proposal was a copy of the internet with rust instead of javascript and typst (a markup language similar to latex) instead of html, but my proposal ultimately wasnt chosen
Personally, I think that if you remove all the javascript quirkyness out of typescript (like the loosely equals operator) and maybe some other cleanups (like how interface and class are pretty much identical) then I think you have the perfect language for the web
And maybe some rust components like implenting traits
i think you're just being casual but since it's a pet peeve of mine: you mean "web", not "internet". it doesn't sound like you want to reinvent IP or TCP/UDP/QUIC, etc (maybe not even HTTP), just the standard languages used by browsers
rust doesn't quite make sense to me here though. you need an interpreted language or at least machine-agnostic bytecode (like webassembly)
(as much as i like rust)
No i think web is pretty much it, the idea was to have two computers not connected to the internet talk to each other
I dont mean it has to be compiled, just saying it would be cool if it had some rust elements like implenting traits)
oh yeah then i'm on board. one advantage JS and other scripting languages have is that they can start being executed while code is still being downloaded, and globally-relevant things like traits can make that tricky, but i'm sure that problem could be worked around
a friend of mine also suggested that such a language has to be compiled, but I wasn't so sure of that
I hope that some day javascript could die and be replaced by something better
also before we go back to modules I also had a name for that language: SuperScript
in math, the place of an exponent is called a superscript because its a script (something that is written) super (above) an expression
Anyway
so where were we