6 ms·
Why C# goes well with TypeScript
- mikece 5y ago"They were both designed by Anders Hejlsberg." Is there really more to say than that?
- tluyben2 5y agoI would like for c# to compile to TS or JS with the same support as ts to js. I know there are projects for c# to js but those are not really well supported. I understand why things are as they are, but it seems a missed opportunity to me.
- ameliaquining 5y agoI don't think this can work. JavaScript and the CLR are very different runtime environments that make different kinds of things available at runtime, and the workarounds for this will have different tradeoffs that will require programmer judgment to resolve. They will never be able to interoperate completely seamlessly. By contrast, TypeScript at runtime just is JavaScript, so there's no gap to bridge.
- rco8786 5y agoThat’s the point of compiling one language to the other. We do this all the time. And yea, you wouldn’t have access to the .NET standard library but you would have access to the JS standard library via some interopability mechanism. Lots of languages compile to other languages with different runtimes.
- tluyben2 5y agoYep, it works for clojure and clojurescript like that. They are enough the same to feel good while not having the same libs/runtime.
- ameliaquining 5y agoI can't think of a language that compiles to a runtime that it wasn't originally designed to target, in a way that permits interop with code written in a different language targeting that runtime, without requiring the programmer to maintain constant vigilance against interop-related bugs. In particular, either the same code has different semantics depending on which runtime it's targeting, or some data types have multiple different not-quite-100%-compatible runtime representations. Kotlin/JS, Kotlin/Native, GWT and its successor J2CL, ClojureScript, etc., all seem to have this problem.
- fulafel 5y agoDirect calls between languages is always going to have some friction because languages have their own data types and cultures, it's unavoidable, but I think many of those systems make it work as well as can be reasonably expected. Meanwhile you have the option of specifying a language neutral protocol for invoking public interfaces across languages, or reuse a wire protocol. Not many people seem to make this tradeoff though, it would usually be a bigger pain than to live with the limitations of cross language direct calls.
- ameliaquining 5y agoYeah, but the top-level comment was asking why C#-to-TypeScript can't be as smooth as TypeScript-to-JavaScript. This is why. (Also, I've definitely seen Protocol Buffers used successfully as a means of cross-language interop. But I suppose this works better if you already have really strong tooling support for them.)
- 3np 5y agoI think it's the other way around. C# is a much stronger language than JS. It shouldn't be a big deal (theoretically) to transpile C# to JS (though you'd have to provide interfaces for any existing JS code you'd like to interact with). The other way - JS->C# - is a lot hairier. Compare compiling a typed language to bytecode vs "decompiling" from bytecode to an unavoidable plate of spaghetti.
- ameliaquining 5y agoIf by "stronger" you mean "less expressive", then I think there are a number of things in the CLR, like value types and reflection, that pose tough tradeoffs if you try to express them in JavaScript.
- 3np 5y agoTypes can safely be erased on compilation, so that needn't be an issue. A bit too foggy right now to have any valid thoughts on reflection, but I intuitively imagine strings can be abused to that end.
- ameliaquining 5y agoSorry, what do you mean by "types can safely be erased on compilation"? What would be the runtime representation of a C# struct in JavaScript?
- tluyben2 5y agoThere are and have been quite a few efforts[0] that 'transpile' c# to js and they worked pretty well (I used bridge.net on a large project and it was nice, but the tooling sucked), but without full support (aka a smooth vsc experience like TS which is simply quite bad for c#, the regular version, already, let alone derivatives) it died. Guess people who worked on it dumped it and moves to TS for client/Server. Seems a waste but whatever; nothing to do about it. [0] https://stackoverflow.com/questions/16434389/javascript-and-c-sharp-cross-compiling-and-conversion https://stackoverflow.com/questions/16434389/javascript-and-...
- tejinderss 5y agoTypeScript is quite a different beast than c# (structural typing, union/intersection types, control flow analysis, emphasis on types manipulation (Partial, Record etc). Even the TypeScript compiler is not following OOP patterns (it's all functions with union types as polymorphism).
- ameliaquining 5y agoThe TypeScript compiler is weird in a lot of ways. Like, all type checking happens in a single 40,000-line file. And it uses namespaces, which are officially soft-deprecated, instead of modules. Point is, I wouldn't look to it as an example of how to write a good TypeScript app. (Also, use of mostly functions with relatively few classes is common in, e.g., modern React; I don't think you're fighting the language too much if you do it.)
- reverseblade2 5y agoAlternatively to both, you could use F# as a single language.
- ameliaquining 5y agoI just can't see having three different general-purpose languages in my stack for a single app (narrowly defined to exclude things like administration scripts, offline data analysis, client-side apps that need ecosystem-specific languages, etc.). For anything this article would suggest using C# for, either TypeScript or C++/Rust* ought to be good enough. The performance/type-safety (if using TypeScript) or development-speed (if using C++/Rust) costs seem unlikely to outweigh the technical and operational overhead of introducing a third language with its own large distinct runtime. In particular, if TypeScript isn't performant enough for whatever I'm trying to do, then it seems likely that there'll be more performance bottlenecks in the future, and so just moving to a generically faster language won't be good enough; I need a language that offers precise control over performance, so that when future issues come up, I know I'll be able to solve them. C# sort of has this with unsafe, but it's a lot rougher than C++/Rust, which is presumably why the article doesn't mention it. I could see using C# instead of TypeScript on the server, with TypeScript reserved for the web client only, but that's quite a different proposition. And if I were starting a new codebase from scratch for, say, a web app, I'd just use TypeScript the whole way down, both for homogeneity and to make it easier to take advantage of server-side rendering, isomorphic business logic, etc., and drop down to C++/Rust (via node-addon-api/napi-rs on the server or WebAssembly in the browser) if this proved to be necessary for performance. * I'd much rather use Rust, but it's definitely the case that if you need to integrate with existing C++ code, no other language today can do that very well. I'm hoping that Rust will be able to do so in the future, so that legacy C++ apps can be ported incrementally, instead of requiring each app (or at best each large component of an app, as in Firefox) to be rewritten all at once. C++-to-Rust will probably never be quite as smooth as JavaScript-to-TypeScript or Java-to-Kotlin or Objective-C-to-Swift, but it might one day be good enough that the benefits outweigh the costs.
- binarynate 5y agoThanks for reading the article! > I just can't see having three different general-purpose languages in my stack for a single app What about for a larger system (comprised of multiple projects) or for a company? I'll give an example. I'm currently developing a cloud-based product to allow multiple people to remotely view and control the same web browser (mostly for virtual and augmented reality). Performance is important due to the real-time communication aspect. The part that interfaces with Chromium is C++, but I want to write as much of the services as possible in a higher level language to speed up development and avoid memory-related footguns. So, I chose C# for the services in the hot path because it's more performant than Node and it's also easier to call into C++. However, the system is really comprised of multiple services, and I still use TypeScript + Node for parts that aren't performance critical, like lambda functions that control autoscaling and the customer-facing web panel. > In particular, if TypeScript isn't performant enough for whatever I'm trying to do, then it seems likely that there'll be more performance bottlenecks in the future, and so just moving to a generically faster language won't be good enough; I need a language that offers precise control over performance, so that when future issues come up, I know I'll be able to solve them. The tradeoff with going all-in on C++ or Rust (for me at least) is that it significantly slows down development. For me, it's really important to be able to move quickly when developing a new product, both because I want to get it to market quickly and because I know I'm going to have to make changes based on what I learn from the market. I can still move fast with C#, and I don't find having a third language as a significant burden (like I mention in the article, I think it's a lot like TypeScript). Also, since it interoperates with C++ easily, that makes it easier to move more pieces to native code in the future if needed.
- trilinearnz 5y agoAs someone who is getting into TypeScript from a strong C# background (i.e. getting pulled kicking and screaming into modern web dev through necessity), this article was incredibly useful!
- binarynate 5y agoHey thanks! I'm glad to hear it was useful : )