But as I browse it, most of the dependencies seem to be build-time, not runtime dependencies (i.e. it seems like most of them are related to Babel). The React comparison doesn't include dev dependencies.
While react-native does have more dependencies than vanilla react, on first glance the list doesn't seem too crazy https://github.com/facebook/react-native/blob/master/package...
Plus I forgot to address this in my earlier comment: that visualizer only shows dependencies. By default it doesn't load any dev dependencies. You can confirm that for yourself by checking out https://npm.anvaka.com/#/view/2d/rollup for example - only the single runtime dependency on fsevents shows up, the dozens of dev dependencies Rollup has don't.
So yes, React Native does ship that overcomplicated graph of dependencies to all its users. I'll grant that at least _some_ of the code in those dependencies gets tree-shaken out.
The line between dependencies and devDependencies got blurry the second npm packages got used for more than just Node.js itself. What's really needed to remove the ambiguity is something like prodDependencies, which would be a subset of the current dependencies, but I don't know if it's really worth it.
EDIT: To be clear - maybe I am REALLY old-school, but every time we did a release, we archived our tool-chain (GCC blah blah, Make blah blah, bash blah blah), our depencies, our vendor libraries and our code, so that IF in 20 years, if we had to rebuild a particular release (12.x) for a particular client (Chase) on a particular platform (AIX), we could do so de novo. Maybe that was overkill, but in a world where everything changes, why wouldn't you snapshot everything for every release?
Maybe I'm old - but I don't trust Quickbooks-in-the-Cloud.
EDIT: But I use 'em!
If not, this should be trivial to replicate today using docker containers.
The thing that made it work, though, was the fire-drills. Once a quarter (at the beginning, later it was once a year), we would go buy about 10 servers from dell and set them up in the common-room and say to the employees. "We just got hit by a meteor last night. Get us up from off-sites, including all company documentation. Re-inflate the company in 4 hours. Start Now". Of course we all failed (sometimes the backups didn't even work!), but we got to the point where we could re-inflate the company in four hours. I was so proud of those people.
A fine grained capability system for packages would dramatically improve the safety profile, and if this were built into package.json and the lockfile we could do the following:
1. Packages advertise what their default capabilities should be limited to 2. Changes in those capabilities are encoded in the package lock file, and can't be changed without the user explicitly affirming them
¹ and other langs with extensive use of package managers and micro-packages
I think Deno does that (the new project by Node's original creator):
Maybe it's a start of better tooling? Kicking out a graph of package/permission call stack might be useful to audit
With tighter snyk integration into npm and the acquisition of npm through ms one could argue that security bar may have risen/will rise but I (speaking as a js/ts dev) am still sceptical. I haven't really looked to deep into stuff like selinux/apparmor/firejail [3] maybe someone can give an opinion on this. I'd wish for something that would be codeified on package level to make review easier and give me some peace of mind.
For now my plan is to dockerize most of my projects and it's dependencies. It should give a little more protection against malicious postinstall scripts.
Unfortunately, I depend more and more on npm modules outside of projects (coc-vim comes to mind/for others it may be vscode etc.).
[1] https://medium.com/hackernoon/npm-package-permissions-an-ide... (2018) [2] https://medium.com/hackernoon/im-harvesting-credit-card-numb... (2018) [3] https://github.com/netblue30/firejail/blob/master/README.md
Maybe it could be solved by type checking during dependency resolution time: instead of just checking version numbers, also check capabilities that transitive dependencies declare.
Maybe you could slowly boil the ocean by assuming that everything that doesn't declare required capabilities implicitly requires the "ALL" capability, and triage+prioritize a growing core of packages that have explicit capability requirements. In my mind it's kind of like purifying functions in a library: you start at the lowest level / leaves of the call graph and make sure they don't do any I/O, and then the things that call them can be made pure and so on up the chain.
That sounds like it would be working. If you declare that your package doesn't need network, and it fails because it used the network, that sounds like a bug was caught.
But npm-snark aside, maybe some lack of trust must come from a highly modular open source ecosystem.
If a library I ship could abstain from unneeded platform capabilities, that would certainly reduce catastrophic bug/attack surface, and I'd sleep better.
https://www.npmjs.com/package/number-is-nan
Want Array#filter/map/reduce? Why that'll be three separate packages:
https://www.npmjs.com/package/array-filter https://www.npmjs.com/package/array-map https://www.npmjs.com/package/array-reduce
It just seems to be the culture of the Node.js crowd to take a library, break it up into functions, and publish every. single. one. as a separate package.
To criticize this organization, you would need to understand why people find that to be valuable and show a better approach.
You’re attributing it to “culture” but there may be deeper, less arbitrary reasons. Look up “ponyfill” if you are interested in learning about it.
I’d rather trust a fairly big library with an organized open source group behind it than thousands of small libraries by unknown developers.
Also the legal team likes this a lot more too. If a data leak occurs due to some library that Microsoft wrote, we have one company to sue. If it's a react package, who the hell do we go after? Most of these are "at will" / MIT license style things, so we are more or less SOL anyways, but legal teams don't like hearing that.
You also get at a more fundamental question. What is trust? Why can we trust a larger organization over a collection of individuals? Are they not the same thing? What social structures make one more trustworthy over another?
There's a great book on this by Bruce Schneier called Liars and Outliers. I highly recommend you read it.
A week!
Of course they don’t hold a candle to “is-number” which has 29M/week
Of course this is completely unrepresentative of reality because “yolo just install dependencies at deployment” may mean it’s downloaded 5 or 10 or 50 times for a high traffic site/service with a bunch of backend installations.
isNaN() has been in the language forever. And in case you really need Number.isNaN() (because it's weird for isNaN('foo') to be true), it's been there for quite a long time too. Not enough to be on IE, sadly, but certainly more than enough to be on the modern JS engines React Native runs on.
So, at least for React Native, the package number-is-nan shouldn't be necessary at all. But it's probably a transitive dependency, and that's basically the problem with all these sort of polyfill packages: you might not need them, but a library that runs on older engines on which you depend (directly or transitively) does need them, so you end up paying the price anyway.
which actually if I look at number-is-nan it returns
return typeof value === 'number' && value !== value;
I never use the typeof value === 'number' myself because I always know if what I'm checking is NaN should be a number of not, but probably that's a bad habit to get into.
Polyfills and single-function libraries are just two different problems with the NPM ecosystem.
KPIs are always the driver. Also for programmers.
This says so much about the sad state of modern software development...
When native development is a last resort.
As an end user why do I care about "openness"? If I pay a premium for my platform, why would I want second rate cross platform software?
Falsehoods HNers believe about how people buy/use software. Didn't stop Slack/Discord from become ubiquitous.
"But native tho" just becomes a circlejerk. Talking about what users care about, most people don't know what native means nor if a given app is it. They don't know if Zoom is using more memory or CPU than it "should".
Other than VSCode for Rust and TypeScript, my own personal computer is as much Electron free as possible.
So don't mistake market share for freedom of choice.
The important thing is features - which VSCode has, and the speed at which those features are developed and deployed on all platforms - where VSCode is nearly peerless.
If developers cared about performance and resource consumption above all else, no one would be using VSCode right now (you included). They’d be using vim, emacs or perhaps Sublime. But that isn’t the case.
So why does HN keep flogging the “electron is bad” meme?
Also, I wonder how much the Electron love overlapps with VSCode, after all many of those developers were pushing for Atom before VSCode was born.
I think Microsoft chose Chromium for Edge mostly because they have big plans for Electron.
Edit: a word missing
Indeed, even Java and .NET are improving their AOT stories, while available since the early days, weren't as widely deployed as they could have been.
I'm just saying users don't care. They'll still use software that has the features they're looking for, on the platforms they use, as long as performance is acceptable.
I'm pushing back against the idea that performance nuts on HN who won't install a single electron app are somehow representative of the population at large.
How many people know that Slack is battery draining monstrosity?
The only people that pay for Slack are companies. The definition of Enterprise Software is where the user is not the customer.
In the famous words of Jobs about Dropbox -- chat isn't a product, it's a feature.
Are you paying for your software or getting whatever you can find for free? If you are paying, is the software's leanness something you value - that is, will you buy some software because it is leaner over some other software that is heavier? Would that be even if the heavier software has more features?
What sort of software have you bought? I'm asking seriously, not trolling - i've bought Total Commander myself exactly because it was lean (check: windows calculator vs one of the most feature packed file managers[0]) but i do not think there are many that value things like that.
On mobile, I’ll pay to remove ads and I won’t use any software or games where I can’t remove ads.
With the economy in the crapper, I’m starting to voluntarily pay more to support my favorite content producers.
Office is not written using one of the cross platform frameworks and is usually only around 3-9 months behind when it comes to taking advantage of new features as Apple releases them.
Plex is server software. The UI is a web page.
R# itself is a plug-in only for Visual Studio for Windows. Yes Rider is cross platform, but I don’t have a need for it.
The only other software I mentioned are games. No one expects a native experience from games.
this is something that you might value but I think it's fair to say it is already a minority position.
phones and the web have become the primary platform for software delivery, and people do not treat their desktop if they even have one as some sort of premium platform, it's a terminal for the internet.
at this point, people are probably more familiar with the look and feel of web applications than they are with native applications and value similarity across platforms over features of individual platforms. The operating system and the hardware are increasingly becoming irrelevant and a detail compared to the web on top.
Who values desktop software enough to pay for it? I know in the Mac market at least, the few indy developers making money are not writing apps using cross platform SDKs.
Plenty of money to be made desktop solutions to life sciences, manufacturing, factory automation, aren't plugging their air gaped dashboards to the web.
Anyone doing music composition, graphics, animation, infotainment systems.
In Europe there are enough Win32, WPF, UWP, Qt related jobs and consulting projects with hourly rates to do a comfortable living.
As for B2C, it is always going to be an uphill battle regardless of the application type, there are only so many application types that one is willing to pay for outside established brands, and SaaS is a much better way to avoid piracy and get everyone to pay.
But either way, you kind of made my point. Consumers aren't paying for applications built on cross platform frameworks outside of games.
In most countries they just need to go the local market or get hold of one of those lists distributed among students.
All those small companies that manage to have their software exposed on shops like Saturn here in Germany, or do direct sales over their web site.
And just because it is B2C, Prosummer or used via a tablet plugged into a docking station, it doesn't stop being desktop software, from the points of view who's paying and selling it.
And regarding games, anyone with experience on the field knows how much harder it is to make any kind of living out of them versus regular desktop software.
The success/failure rate is much higher, with the large majority of studios never making any dime.
And if you look at the end consumer software which have billions of users, who in one way or the other pay for it, it's almost always built on web tech these days. Discord, Skype, Slack, Spotify, and so on.
Of course there's professional or industrial software written in native code. But that's not because it's popular, it's because it's niche and specialised. The business model of charging upfront isn't exactly a sign of popularity, if anything it's the opposite.
No one cares about the Spotify UI. People don’t interact with Spotify that much. They listen to it.
The business model of charging upfront isn't exactly a sign of popularity, if anything it's the opposite.
In a capitalist system how else do you measure value than what people are willing to pay enough for to have a sustainable business? End users aren’t paying for Slack. They are using the free plan because it’s good enough.
Are you just going to find a different reason why you're going to ignore software built on a web tech-stack? Add up the market valuation of all companies using web technology to bring software to their users. Then compare it to the native market. It's not even close.
It's perfectly fine to use market value to estimate utility in a capitalist system. You just can't ignore every piece of software you don't like.
More developers, more applications of software.
At the same time, performance has a tangential relationship with computer code being interpreted or compiled to native.
After all, Java is compiled to byte code and powers plenty of high traffic servers efficiently.
Many AAA games use ActionScript, Python, Lua, etc for their UIs and scripting for mods.
While it's true that there is no substitute for code compiled to native when high performance is called for, I think it's justified for native development to be last resort.
This is coming from someone who codes primarily in C++, where high performance is important. I wish I didn't have to.
How well has Java done on the client in the last two decades?
Many AAA games use ActionScript, Python, Lua, etc for their UIs and scripting for mods.
What's the actual performance sensitive parts written in?
So I am not sure what you are saying. Everyone that is able to is compiling their stuff to try to regain some efficiency.
The reason is that people wants to do more complex things with their software nowadays, and hardware can't keep up with the trend. There is also battery life, smartphones, tablets...
Those are the reasons we are seeing a resurgence of native development.
This isn’t just me being a Mac snob. I found Apple’s few Windows apps over the years to be just as bad.
Yes and a long time ago Sun came out with Swing. How did that work out?
Even before that MS came out with P-Code and the abomination that was Word 6 for the Mac.
I think it clearly shows that complex UI apps require cross platform UI, or will remain single platform (Xcode, Visual Studio).
I was at a crossroads in 2008. I had been developing mostly in C for a decade and decided to pivot to being your standard “Enterprise Dev”. I had a choice between moving my career to C# or Java. I chose C# partly because of the bad stench of the cross platform Java IDEs at the time. Give me VS or Xcode any day over a Java based IDE.
Photoshop definitely isn’t using a non native runtime. I doubt that Blender is either.
But for writing C# apps in a Windows computer, the old VS was already miles ahead back in 2010. It is a really good product. It had RAD tools, testing, deployment, source control, database migrations, all wrapped in a very snappy and convenient GUI that I still don't think VS Code replaces properly. As much as I love the command line and unix philosophy, there was something about such a complete IDE that made me very productive. All IMO of course.
However I strongly believe that VS Code will get better and better with time and be able to fully replace old VS even for this use case in the future.
Why would you think React Native would be less bloated than native apps?
What are some well done cross platform apps that don't unnecessarily drain battery life? I can think of one - VSCode.
You're talking about Electron there, which like phonegap is a browser wrapper and a different thing to RN. I don't believe RN is known to be a battery drain in general.
React Native for Windows and Mac specifically, none. We commenting on an article about its launch. It's a bit early to be talking about that.
Cross-platform frameworks like Electron or Flutter, loads. VSCode, Skype, Discord, WhatsApp Desktop all use it. Of course you might argue that they're all selling services rather than software but that the point really is that the companies authoring those apps want to keep costs down, give users the same experience everywhere, and believe cross-platform apps can give users a good experience.
If you want to know what it's like to have everything break LITERALLY every few days, use react native.
The update wasn't terrible.
Its annoying, but I succeeded in upgrading in one project in about 1 hour. Just basically comparing the example code diff on github.
perhaps older version had more changes and weren't documented as well.
irrelevant comment: I hate Expo as it fails to be a helpful abstraction on top RN.
My favourite is the factorio research tree. It gives you a sense of depth and you can select dependencies.
Maybe I'll implement it one day when I have the time.
Fortunately, in such industries you don't have to worry about being cross platform particularly. Go write C# and WinForms (or whatever it is these days). Or use Lazarus/FreePascal if you do need to be cross platform.
This also voids the argument "we need Electron, because it reduces development costs, and we can get truly cross-platform apps". Ripcord is written by a single indie developer and runs on Windows, Mac, and Linux. Imagine what could be done if Slack employed a team with 10 Qt developers.
Most web apps are egregious. The problem is that there is a whole generation that is not exposed to Delphi or Qt Designer and have the false believe that developing web apps is an order of magnitude easier. It's only an order or magnitude easier for them, because web tech is the only thing they know. Heck, I was writing GUI apps as a 12y/o with Delphi.
They will definitely notice. E.g. baseline MacBooks (which is probably what most people outside developers buy) still come with 8GB RAM. If you subtract the OS, video memory, and some disk caching. There is not that much left on modern macOS (or Windows).
Having Slack + Skype in the background and some tabs open with modern web sites/applications can easily much a few GBs of RAM, slowing down quite a lot of 8GB machines. I guess most developers just don't notice, because their employer give them development machines with 16 or 32GB RAM.
People don’t care.
They don't care because they don't understand. They will just believe that their computers are slow and that they have to throw more money at it. Or they just buy an iPad and it will feel fast, because Apple does not allow every application to ship and run its own web browser.
no offence to the dev of ripcord; IMO qt and gtk stuff always just looks super outdated
That's because the developer decided to use their own theme. I have made a few Qt apps and on macOS and Windows you can barely distinguish them from a native app, unless you know where to look. Fully agree with Gtk+ though, it does not follow platform styling and conventions and is very slow on macOS (don't know about Windows).
That might still be better (I'm undecided, personally), but it's worth recognizing that heavy native app is still there, just shared with a lot of other JS apps.
I understand the rationale for going async -- you can never be sure exactly how long anything will take, and invisible things like memory management and caching can blow up your runtime; and if you get synchronous operations wrong, that leads to spinning beach ball cursors and “app not responding” errors, which are even worse than lag. But in that scenario, an async app isn’t going to perform any more usefully, you’ll just get a blank or frozen screen instead of a beach ball.
Imagine how much more enjoyable npm would've been if prominent JS devs took a sane approach to dependencies, like the TypeScript team who have no runtime deps.
The resulting npm deps of hell [1] means they need to rely on complex build solutions like Webpack to manage it all. My preference these days is to avoid npm/yarn all together and just use TypeScript watch (tsc -w) for incremental updates which lets you develop modern JS using modern fx's (e.g. Vue/React) without any of the npm/Webpack complexity & only requires a vastly simpler build solution to minify/bundle all UMD deps together.
[1] https://www.reddit.com/r/ProgrammerHumor/comments/6s0wov/hea...
I'm actually surprised, I thought React had many more dependencies.
Edit: Removed comment related to typo, no longer relevant.
The core library deps isn't relevant, it's how many deps the smallest starting Create React App has that matters [1]. As mentioned by OP react-native is far worse.
Also, with TypeScript, Babel becomes completely unnecessary. I haven't used it in any of my React projects for years. Many templates still include it by default to match the JS version, but if you create the project from scratch without any scaffolding, there is no reason to do so.
You can see all the dependencies it installs by running:
$ npx create-react-app my-app
> Also, with TypeScript, Babel becomes completely unnecessary.Right, as per my comment it's also my preferred approach:
> My preference these days is to avoid npm/yarn all together and just use TypeScript watch
In general I prefer Vue over React, but I prefer to use vanilla TypeScript & UMD deps to develop with either.
> Many templates still include it by default to match the JS version
It's what the React team is recommending to start with [1]:
> Create React App is a comfortable environment for learning React, and is the best way to start building a new single-page application in React.
[1] https://reactjs.org/docs/create-a-new-react-app.html#create-...
However, the resulting `package.json` only shows 3 dependencies: react, react-dom and react-scripts. After `yarn build`, it added 3 more things from `@testing-library` (https://testing-library.com/), I assume those things won't make it into the production bundle.
react and react-dom only depend on a tiny number of things, you can check that with any dependency visualizer. 6 or 7 in total for the whole tree, and most of those are tiny things that they just split off from react itself (e.g. prop-types).
react-scripts is the huge beast that causes the dependency tree to explode. It is a `create-react-app`-specific package that contains all its build logic. So that seems to confirm the hypothesis that there actually aren't many runtime dependencies in the basic template, but who knows what it does behind the scenes. Also the LICENSE.txt file it generated for the biggest output .js file only includes entries for react, react-dom and object-assign.
No idea about React Native.
> No idea about React Native.
The OP suggests it's worse. But I no longer use React Native as I kept running into bugs & UI issues that were never fixed. I ended up reporting a few with complete repro's but didn't look like they were ever looked at, instead after a few months they decided to triage their 1000s of open issues, to get back to zero issue inbox.
IMO React Native is architecturally flawed to run into so many issues when creating normal Apps after years of development, maybe if there were more developer resources on the team it would be more manageable. But I believe Flutter has a much better architecture [1] which feels much more integrated & polished that results in a more responsive app that works as advertised.
For mobile right now, the easiest, most headache-free solution may actually be to forget about cross-platform and just do separate Android and iOS native apps. You won't need to do things like hunt for a bunch of 3rd party libraries whenever you need to use Bluetooth or something.
Once SwiftUI and Jetpack Compose mature, that process should be much more pleasant as well.
It definitely isn't, Dart is an advanced clean, strongly typed classical language without JS's warts that's just as clean & productive with a clean complete & well-defined standard library, native support for modules, consistent async/await in all libraries, etc.
I love TypeScript, but it's major productivity advantage over Dart is in JS's dynamism, something that's a lot more restrictive in Dart because it needs to support AOT, which is what allows it to compile to native code & advanced linking + tree-shaking, resulting in its better performance. So there are areas where you need to use code-gen, but having wasted an eternity trying to diagnose runtime issues in C#/Xamarin in libraries that use reflection, I'd much rather use an AOT language that only provides language features that natively supports AOT then running into frequent on-device issues that only occur at runtime.
> For mobile right now, the easiest, most headache-free solution may actually be to forget about cross-platform and just do separate Android and iOS native apps.
Nope, Flutter's Reactive UI & live-reload is far more productive then developing using native iOS or Java/Kotlin tools (which can also be used in Android Studio). SwiftUI is close if you just need to develop for iOS, but I find Dart/Flutter to be a lot more productive than using Swift & Xcode's woefully poor tooling support.
It also doesn't seem to have things like sum types, which would be pretty easy to do in an AOT language. The expresiveness, the ability to accurately describe data structures with its type system just doesn't seem to be there. It seems about on par with Java in that regard. Fast live reload is pretty good though, I hope other langauges/frameworks put more effort into that.
I haven't used it much beyond simple demos though.
TypeScript is even worse in that regard since it has to deal with JS that wasn't written in TypeScript & there's no way to verify the runtime object complies with the interface you say it does. Then of course JS has to deal with multiple null & undefined values & even more falsy values, ultimately TypeScript provides nice static analysis but also a false sense of security as there's no guarantee that the compile time static analysis matches the actual types / values at runtime.
At least with Dart, you're guaranteed everything is written in Dart so you can have confidence in the static type analysis is actually going to be valid at runtime. With that said you can use the `--enable-experiment=non-nullable` to enable its Sound non-nullable Types feature [1]
> The expresiveness, the ability to accurately describe data structures with its type system just doesn't seem to be there. It seems about on par with Java in that regard.
This is a gross mischaracterization that I'm just going to assume you're familiar with Dart at all. It's vastly more modern and less verbose than Java in basically all aspects: type declarations, auto properties/getters/setters, auto constructors, implicit interfaces, factory constructors, mixins, typedefs, inference, lambdas, async/await, extension methods, optional parameters, string interpolation, single integer type, cascade/chaining, null guards/assignment/coalescing, generators, operator overloading, Callable classes, first class functions, everything's an object, duck typing with noSuchMethod, etc.
More often this can happen with external data (typing incoming JSON responses), but you have to run-time validate those anyway.
`null` is only rarely used in JS, `undefined` is by far the more common one, and of course the types reflect which one is a possible value, so it's not like you can miss it by accident.
Falsy values are only a problem with bad practices - inside `if`, I just always use the full form with the `===` operator, e.g. `if (variable !== undefined)` instead of `if (variable)`. A lint rule can be enabled for that. There is now also the `??` operator which prevents the common misuse of `||`, e.g. `const a = variable ?? 'default'`.
So those things aren't really issues in practice.
You are correct in assuming that I'm not very familiar with Dart, I have only used it very briefly. I have only checked whether specific features such as sum types were available.
That's not true, `undefined` is not even a keyword or type, `null` is what you would use if you wanted to specify a variable has "no value" in JS or JSON (again because `undefined` isn't a Type). The "undefined" value is only for specifying if the variable "does not exist". The difference is important as the behavior is different depending on how you use them.
> I just always use the full form with the `===` operator, e.g. `if (variable !== undefined)` instead of `if (variable)`
This is bad practice as you're only testing for `undefined` here, not `null`, this is basically the only time where strict equality isn't useful. You want to test with `if (variable != null)` which tests for both `null` and `undefined` and not other falsy values that `if (variable)` tests for.
> There is now also the `??` operator
Right, the Nullish coalescing operator (which Dart/C# also has) tests for both `null` and `undefined` (well `void 0` since the `undefined` value can be overridden) and not falsy values.
So if I have a type `User|undefined`, testing `if (user === undefined || user === null)` is pointless, as `null` is not part of that type. It would be different if it were. Similarly, it makes no sense to test a variable of `User` type for value `false`, like it would if the type were `User|boolean`, or even `User|false` which you can do in TypeScript (not that you should). So `if (variable)` is still bad (ok for booleans, tolerable for some types but better avoided). You only test for what the variable can contain.
Some types you encounter are `T|null` - mostly DOM things (e.g. the return value of getElementById), but some JSON stuff as well like you said. Even though a lot of JSON just has optional properties instead, which for all intents and purposes work like `|undefined` when reading them.
From my experience, it is much more common to deal with `undefined` in the JS ecosystem, whether that is by omitting properties from objects, or explicitly assigning/returning `undefined` somewhere.
`T|null|undefined` types are ever rarer. Only for those it makes sense to test for both null and undefined.
By the way you can also have types like
type RemoteData<T> = {ready: false} | {ready: true, data: T}
in TypeScript, which is better than { ready: boolean, data?: T }
because you don't have to worry about "does `data` still make sense when it is non-ready?", the type clearly tells you that it doesn't (of course you can also have a different type where it would, the point is to accurately describe the structures you deal with). Then, if you do a check if (remote.ready) {
console.log(remote.data.length)
}
it knows that data exists inside that `if` block, so you can safely access it without `!` or `?`. Similarly, inside `if (!remote.ready) { }`, you cannot access it at all. It also won't let you pass an object with { ready: true }, but no data of the required type to `RemoteData<T>`.It's very relevant, your TypeScript definition is meaningless at runtime when it's executed JS where all TypeScript's type information is erased, the only checks are relevant are the runtime JS type checks.
> `if (user === undefined || user === null)` is pointless
Right, it is verbose & unecessary, so is only testing for `if (user === undefined)` which is inadequate and I don't know anyone who'd use it since using the recommended `if (user == null)` is shorter and more complete for testing if any value is not `null` or `undefined`. If you're validating JSON you should know that there is no `undefined` type in JSON, but any value could be `null`.
> From my experience, it is much more common to deal with `undefined` in the JS ecosystem, whether that is by omitting properties from objects, or explicitly assigning/returning `undefined` somewhere.
If a type want's to declare that property exists but doesn't have a value it would be `null`, which is also the only option you have in JSON to do so.
Your TypeScript definitions are for your code structure and API description so you can benefit from its static analysis, but you should be aware they do nothing at runtime where all Type annotations are erased so if you try to define your Vue component with an optional property, e.g:
class MyComponent extends Vue
{
p1?:string;
p2 = null;
}
It gets stripped away completely but setting a null value instead will ensure the property exists and is made reactive: var MyComponent = /** @class */ (function (_super) {
__extends(MyComponent, _super);
function MyComponent() {
var _this = _super !== null && _super.apply(this, arguments) || this;
_this.p2 = null;
return _this;
}
return MyComponent;
}
It's important to know what guarantees TypeScript does for you, what effects the type annotations have and what their behavior is at runtime.But there are only a few ways in which that can happen:
- a bug in type definitions - a JS library with .d.ts files which "lie" about the actual types - this is no different than any other bug in a library, needs to be reported and fixed. In my experience, such bugs are not very common (I've yet to encounter one).
- non-validated external data (JSON coming from HTTP) - like I said, you have to validate external data (or assume that anything can be anything). You kinda have to do it in all languages, though ones with reflection and a deserializing library can do that somewhat automatically and throw a runtime error if the deserialization fails (although that is not full validation).
- incorrect explicit casts and using `any` - e.g. `const a: number = ('asdf' as any)`, but less stupid and more accidental. This is a bug in the casting code, similar to doing an incorrect `reinterpret_cast` in C++. There is usually little reason to do explicit casts in TypeScript code, outside of very small isolated pieces of code.
Which means you generally don't have to worry about any of this. Relying on those guarantees is good enough for 99+% of situations (I mean, some people even use dynamically typed languages and survive without doing tons of checks on every other line of code).
---
Testing stuff which is not expected (by the specified type) to be `null` for `null` is just as pointless as testing it for the number 10. There is just no "valid" way for the `null` to have gotten there (just like the number 10). It would be extremely paranoid and only add noise to the code.
If there is a valid way, then the type needs to be `T|null` (and then you need to test it), not `T`, otherwise it's a bug. For TypeScript code, this will be checked automatically, for JS library type definitions, it needs to be made correct manually.
Regarding JSON and undefined, you can omit properties in JSON. E.g. sometimes have {"user": {"name": "Bob", "email": "[email protected]"}}, and sometimes just {"user": {"name": "Bob"}} without the email. Such an optional "email" can of course be expressed in TypeScript, and can be tested as `=== undefined`, which will return true if it's not there. And such a pattern of omitting properties from objects (not just JSON) is much more common in JS than assigning `null` to stuff.
You are much more likely to find a JS object where some property is sometimes there and sometimes not there but never `null`, than an object where it is always there but sometimes `null`. That's what I mean when I say `undefined` is much more common than `null` in the JS world. But neither is a problem, you just need to have types which correctly describe what values the properties can contain.
---
So typically none of this is a problem in practice, as long as you have correct type definitions for the JS libraries which you use (i.e. there is no bug in them, just like there should be no bugs in the library itself) and don't do funky casts with `any`.
Unlike most languages, TypeScript is just a high-level static analysis compiler service that compiles to JS that executes in a JS VM. It has no control over what happens at runtime, it doesn't know about external libraries and user input, how its TypeScript functions are going to be invoked. All it can know is the "truths" you tell it to assume, of which it makes no attempt to validate whether any of your assertions are accurate. It's not that TypeScript is wrong as it can only verify the compile-time state of your program, it doesn't know or can control the runtime state of the JS VM, what arguments your functions are invoked with, what values properties are set with, how any of its instances or prototype chain is manipulated, etc.
> Testing stuff which is not expected (by the specified type) to be `null` for `null` is just as pointless as testing it for the number 10. There is just no "valid" way for the `null` to have gotten there (just like the number 10). It would be extremely paranoid.
It's strange to read runtime JS type checks is pointless when it's the only way you can validate for sure what a Type is. You seem to think you can resolve issues by declaring typescript annotations in a different way, when they have absolutely no impact, your type annotations does not provide any guarantees at runtime, TypeScript can't tell you if your Type annotation is accurate now or will remain accurate in the future, if what you cast to is accurate, if how your code is invoked is accurate, you're telling TypeScript what the only types for a variable are, but these type assertions have no impact at runtime. Ask yourself if you're only checking for `undefined` what the behavior of your program is when it's called with `null`. Since JS functions have positional arguments it's very common for it to be invoked with `null` argument values when needing to provide values for each argument, whereas it's almost never explicitly called with an `undefined` value unless it's undergoing regression testing for bugs.
Given any JS variable can be assigned both `undefined` and `null`, there's no good reason for using strict equality check for `=== undefined`, it's always the wrong type check unless you need to determine the difference between `null` and `undefined`, otherwise it's just a more verbose inadequate type check for nothingness.
In practice, say I have
type User = { name: string, email: string }
let loggedInUser: User = { name: 'Bob', email: '[email protected]' }
or even // Can't change the contents, only reassign the whole variable
let loggedInUser: Readonly<User> = ...
and only ever use that `loggedInUser` from TypeScript code (because my entire codebase is TypeScript), and I avoid the 3 scenarios mentioned above (buggy JS library type definitions, non-validated external data, casting/any/`!`).How would a `null` email ever get inside `loggedInUser`? It just won't happen. I know there are no run-time checks - I don't need any run-time checks. I don't need 100% theoretical guarantees. I can be reasonably certain that `loggedInUser.email` will always be a non-null non-undefined string. It's a good enough™ practical guarantee. A null-check on `loggedInUser.email` would be pure confusing noise (because anyone reading it would go "wait, this can be null? I thought it was non-null").
Do you have a practical explanation of how a `loggedInUser.email === null` situation might occur given the above assumptions?
>Given any JS variable can be assigned both `undefined` and `null`
Any JS variable can be assigned literally anything. I don't need to check that `loggedInUser.email` is not null, just like I don't need to check that `loggedInUser.email` is not a boolean or a number. Because how would that even happen? Not having to do those checks is half the point of having a static type system in the first place (the other half is being notified of type errors at compile/edit time).
If you need to defensively check whether something so basic that is never supposed to happen has happened, then the code is already a giant unmaintainable mess.
E.g. `const a = [1, 2, 3]` will let you do `a[5]` and still give it type `number` instead of `number|undefined` as mentioned in the github issue. Many other languages also do this (though they have runtime checks/errors).
So that kinda sucks, but the rest still stands (there is still no practically realistic way for `null` or anything other than `undefined` to get there). Hopefully they'll fix that in the future with a new compiler setting.
Or not. I've worked on plenty of applications that had few if any dependencies for those things. I'm sure many others have too.
In some cases that was because we didn't need that particular functionality. Routing has little value if you're building an in-house SPA that always starts from the same dashboard anyway, for example.
In other cases, it's because we're programmers and don't import entire library ecosystems to do what we could do ourselves with a few lines of code or some APIs that are already supported by all modern browsers anyway.
I liked React when it first arrived, because it was a tool that was that did one useful job and did it reasonably well. I dislike the direction it's taken more recently, because it now seems to be trying to do several jobs and not doing most of them very well at all. I understand that this is partly because of the way some developers coerced React into doing things it wasn't really suitable for and the React dev team have been responding to that, but I still think value has been lost in that process.
https://hacks.mozilla.org/2019/11/announcing-the-bytecode-al...
It really doesn't bode well for microservices of any large scale complexity, unless there are concentrated meganodes with limited interconnects like cities and superhighways.
Bloat though ... I mean, if every npm module was simply a directory with a package.json file and a couple js files I'd be happy. But thats almost never true, and usually for bad reasons. I'm not sure how to fix the problem. A few years ago I worked with a guy who maintained a popular little 200 line react image component on npm. The project website was great - with example images and whatnot. Some software we worked on used his library. Our node_modules was huge, and one day I took a look to try and figure out why. It turned out his tiny module was bundling all ~10mb of example images in the package itself.
He was shocked and embarrassed when I pointed it out to him. The library had thousands of stars on github at the time. Lots of people were using it but nobody had noticed and mentioned it to him.
10mb isn't that big, but this is the sort of sloppiness that really adds up over time & thousands of transitive dependancies. Would tooling fix the problem? Maybe a little, but I suspect the problem its partially cultural. A lot of the web development community suffers from a lack of ... thoroughness. Like, the expectation is if the website works and looks pretty, you've done a good job. And invisible bugs and issues get overlooked consistently. Like app bundles which silently include multiple copies of the (200k) moment timezone database. Or obvious security issues that web devs just don't know to look for. I suppose this is how juniors learn - but it feels like a very lonely place sometimes when you have skills and experience.
Meanwhile WinAmp was sooooo tiny.
It would be a huge quality-of-life improvement for React developers, not to mention the improved security and reliability.
http://npm.anvaka.com/#/view/2d/react-native
From my experience, it's really great to work with and definitely saves a ton of work, but the depgraph above fills me with doubt for use in sensitive applications such as in finance or healthcare. For this reason, I've been trying out Flutter or even considering to go back to native apps. Perhaps there's some kind of middle ground where we can create a tight microkernel-like thing natively using secure enclaves and key managers, but expose an API to the "untrusted" parts of the program. This approach is not without its own downsides, such as dark patterns in a compromised UI. However, as one friend pointed out, a lot of those deps are indeed for build time only, which have different risk profiles.
The depgraph of reactjs is far simpler and easier for me to understand and therefore feel trust:
http://npm.anvaka.com/#/view/2d/react
Does anyone know if there has been reliable research towards the security of the entire RN dependency tree? Seeing a stray dep there that has 1 maintainer on npm/GitHub who has been inactive for over a year makes me nervous. Any one of those JavaScript projects could do something nefarious deep under the hood, and this to me seems to expose a huge surface area for attackers.
Here's a classic throwback to keep us on our toes :)
https://www.win.tue.nl/~aeb/linux/hh/thompson/trust.html