The only point I take slight issue with is Avoiding Namespaces.<p>I can't speak for frontend code, but on the backend:<p>It feels at least somewhat obviously true that unique names are good. Even if you aren't operating in a language which has global imports (which is most nowadays), unique-as-possible names can help disambiguate-at-a-glance something like:<p><pre><code> const user: User = await getGoogleSsoUser();
// 100 lines later...
console.log(user.microsoftId); // wait why isn't that field available?
// ok i'll fix this
const googleUser = await getGoogleSsoUser();
// obviously that makes sense; but what about the type?
export function getGoogleSsoUser(): Promise<User> {}
// wait... should that return a Google API user object? or our own user model?
// let me scroll 200 lines up, ok its defined there, open that file...
// or just:
export function getGoogleSsoUser(): Promise<GoogleUser> {}
</code></pre>
Contrived example of course, but it's a broader pattern I see every day; there's a lot of overloaded terminology in programming.<p>But this gets hairy really quickly.<p><pre><code> // google will provide these types... but lets assume you're writing your own
export type GoogleUserV1 = ...;
export type GoogleAPIV1GetUserResponse = {
user: GoogleUserV1,
}
export type GoogleAPIV1ListUsersResponse = {
users: GoogleUserV1[],
count: number,
}
// ok lets import them
import { GoogleUserV1, GoogleAPIV1GetUserResponse, GoogleAPIV1ListUsersResponse } from "my/service/google";
</code></pre>
First, the type names get really long, which makes them hard to read at a glance. Second; this cost is replicated anytime someone wants to import something. Third, they oftentimes become a seemingly randomly ordered set of words written like a sentence; why is it not "GoogleV1APIListUsersResponse" or "GoogleAPIListUsersV1Response"?<p>We can solve the second problem by doing an old-style wildcard import:<p><pre><code> import * as google from "my/service/google";
const user: google.GoogleUserV1 = await getGoogleSsoUser();
</code></pre>
But this almost always ends up stuttering, because the producer package still wants to guarantee unique-as-possible exported names, as asserted above. So we made problem 1 worse, and did nothing for problem 3.<p>With namespaces:<p><pre><code> export namespace Google {
export namespace User {
export type V1 { ... }
export type GetResponse { ... }
export type ListResponse { ... }
}
}
// now to import it
import { Google } from "my/service/google";
const user: Google.User.V1 = await getGoogleSsoUser();
</code></pre>
The symbol, as a whole, isn't shorter. But, it's easier to read (and write!). It also helps disambiguate where in the symbol each component of the type's name should reside, when the producer wants to for example add a new type or function.<p>The argument against presented by the article boils down to: it creates unnecessary fluff in the emitted javascript. That's a reasonable argument; it does. In practice, it's more nuanced. First: I've never seen it cause an issue. So, premature optimization, YMMV, etc. Second: the fluff is erased for types anyway; so it only becomes an issue for functional code defined like this (all of my examples were in types, but its easy to imagine a Google.User.List function). Third, though not a direct counterargument to the article: it's literally how Google organizes the types we've been talking about [1] (though, how they organize the functional code, I'm not sure).<p>[1] <a href="https://github.com/DefinitelyTyped/DefinitelyTyped/blob/master/types/gapi.people/index.d.ts" rel="nofollow">https://github.com/DefinitelyTyped/DefinitelyTyped/blob/mast...</a>