Porting a React Front End to TypeScript
executeprogram.com
executeprogram.com
Typescript will pick up the JSDoc type annotations and use them to type the code. This can be a great option when typing an existing project.
Docs: https://www.typescriptlang.org/docs/handbook/type-checking-j...
Recently, Typescript was complaining about an implicit `any` even though the VSCode tooltip clearly could infer the actual type (it confusingly was showing both cases in the tooltip). I finally realized that VSCode's built-in inference worked here but Typescript didn't work at all because I forgot I was importing a .js file rather than a .ts file.
VSCode for course also downloads @types/* files in the background even in vanilla JS projects which is super helpful because you get effortless intellisense. That it does this kind of stuff out of the box is the sort of reason why I've lost my Vim/Emacs fanaticism over the years.
VSCode tries to give you type info in contexts where Typescript wouldn't (e.g. importing Javascript files, in a completely non-TS project) so it makes sense that its inference tooltip can be more helpful. You can easily recreate this by importing a fn from a JS module and then hovering it in VSCode (also configured for Typescript): VSCode knows the fn signature but Typescript won't. Both cases show up in the tooltip (though confusingly).
At least, that's my interpretation of this sort of tooltip: https://i.imgur.com/lXS5teK.png
And to be clear, your last sentence was my exact praise for VSCode at the end of my own comment.
Are these coming from DefinitelyTyped?
It doesn't auto-download @types, but it does suggest them to you. It can also auto-import, rename across files, etc.
Re-using types (structs or union types) is also a huge pain.
Perhaps others here will find it useful as well.
https://github.com/typescript-cheatsheets/react-typescript-c...
If it seems more hassle then it's worth for what you're working on, the rest of your team isn't bothered, and your clients are happy you don't have to worry too much. I still throw in vanilla JS on other smaller projects every once in a while for those reasons.
[1 EDIT] at most? hahaha.
E.g. if I need to add a Bar property to a Foo object, in plain JS you just do it as and when you need to without any extra hassle. This makes hacking something together really fast and low-friction which is nice.
Typescript wont let you do that though - you need to go off and define the Bar property on Foo which you might argue slows you down, or seems inappropriate if you only need Bar in certain circumstances and not every time or whatever.
Personally I find that the extra rigor that Typescript forces is way worth the extra hassle - it prevents so many subtle bugs, makes refactoring a lot easier, helps multiple people work together on the same code in a sensible way, and IDEs work so much better (in my experience at least).
Most popular libraries by the way all have the types defined already - check out https://definitelytyped.org/
I just want to add a property to an object. All I have to do is add it to the definition, and TS will show me every location I have forgotten to set the Bar property, which means I can be confident it is set, so I do not need to write extra code that tests whether Bar is set.
Yeah this is what I was getting at - e.g. say I have 5 functions that all return Foo object, and for just one of them I need to add in an extra Bar property then I need to make sure that all 5 functions also do the Bar property, even if only 1 needs it (or make it optional, but that might screw with the semantics of the one function that does need it). So now I have a Bar on all Foos, even though only 1 function needs it - things start to get messy.
The alternative to changing all 5 functions is just to create a separate type for just that one function that needs Bar
Either way it is "extra work" if you are used to the fast and lose javascript way of just adding it there and then and not caring about the others.
I agree though that TypeScript is way superior as you point out it would just tell you where you screwed up and I would always start with a new TS project rather than JS today, but I still think there is a place for the raw & dangerous world of untyped JS for rapid and unsafe prototyping and hacking where TS can slow you down.
type Foo = {
Hello: string;
Bar?: string;
};
But if you really need separated types, the extension syntax is so short that you could define it in the function definition directly: type Foo = {
Hello: string;
};
function hello(myparam: Foo) {}
function world(myparam: Foo & {Bar: string}) {}So in development, I am hack together things and though the type checker complains and my IDE shows plenty of red marks, it will still compile.
Once I’m don’t experimenting, I fix the type errors, and refactor.
I personally love TypeScript, but I do have one big hang up. Janky builds in testing. Can't explain it, but sometimes the guarantees TS is supposed to provide don't compile over. Mainly while using nodemon or another auto compile. Have only ran into it a couple times, but it mainly crops up during module linking.
Also keep in mind you can use as modules via require('') and skip adding types to a js lib. Be sure to add --module commonjs or the equivalent in config.
Why I like TypeScript for myself is writing modules and api's. Mainly: inline documentation. And the pursuit of more of a deterministic outcome in your programs. Still the linking issue bothers me.
People don't use static typing for writing code faster, they use it for code that can be READ (and understood) much faster, especially by somebody who doesn't work with that specific piece of code every day.
I think it's generally agreed that in most situations, reading code is much more common than writing code, so static typing really make sense.
You nailed it.
I agree, this is the biggest benefit of static types.
I worked at on a several hundred thousand line JS code base at a company, and people were passing objects around, and it was extremely painful to trace code and figure what the structure of the object was. I had to set a breakpoint in the browser, and inspect the object during runtime. Moreover, some fields would randomly be missing, because the field wasn't necessary for that instance of the object. It was infuriatingly maddening.
I ended up spending a lot of time adding Flow types to it, of the form:
type Foobar = {
someField1: string,
someField2: number,
someField3: Baz,
fieldThatIsNotAlwaysThere: ?Qux
...
}
The untyped state of the code base gave me an extremely hard to resist to add Flow static types wherever I could. I also added a step to the pipeline (with my manager's support) that would break the pipeline and make it impossible to merge new code, if it didn't have Flow static types (and I used flow-coverage to make sure the "any" keyword wasn't being used excessively to side step Flow type checking). I was told by some of my teammates to stop forcing types down their throat. I eventually spent so much reworking large parts of the code base, and adding static types to it that my other work suffered (and I wasn't putting as much time as I should have into it), that I was told to stop spending so much time on adding Flow static types. But it was hard to resist the temptation. When I had to implement a new feature / change a file, I would add Flow types to it, and then be drawn to adding types to the various other files that it connects to (imports from, passes data to, etc). They fired me in the end, for that (not prioritizing the things I was supposed to do well enough) and other reasons (was going through relationship issues and eventually a bad breakup, which caused associated psychological/personal/self-care issues).I've learned my lesson. Dynamic types aren't my cup of tea, and I find dynamically typed code to be repulsive and quite nauseating.
This problem can occur in statically-typed languages too, such as if you have a class to model your entity, but in this instance you only need certain fields to be hydrated. The other fields may be set to null.
This might only a problem if the half-populated instance is 'leaked' to somewhere that expects a fully hydrated instance. Thinking about it though, it's possible that null could also be used to represent a null held on the database, rather than not hydrated.
The ideal solution would I suppose be to roll your own type for this semi-hydrated data, but that's not always possible/convenient.
Example: https://github.com/microsoftgraph/msgraph-sdk-dotnet/blob/de...
`let draft : Partial<Foo>;` says that 'draft' is shaped like a Foo, EXCEPT all of the fields are optional.
If you try to access a field on draft that doesn't exist on Foo, it's a ts error. If you try to pass draft to a function that takes a Foo, it's a type mismatch.
I would love to have static types in JS, but not at the expense of node.. and not just so people who are in different situations than mine are happy, because I act as if I was in their situation.
What do you mean by this? I use TypeScript with node all the time.
Only in the beginning / short-term when the project is new, small, and fits in your head.
IMO doesn't take much more code and complexity for it to switch over to statically-typed code being faster to write.
As an extreme example, I run an online strategy game implemented in Elm. The game only supported three melee classes but the community made really good points about how ranged classes should work.
I came back to a codebase I hadn't touched in over a year, picked a spot in the code where I knew my physics would have to be updated to handle projectiles, started implementing it, and I basically followed the compile errors until my physics system supported projectiles.
Had it been dynamically-typed, this kind of refactor/overhaul would have required me to recredentialize in much more code and either rewrite tests and/or manually test my code branches at runtime to track down errors. It would have taken much much longer.
> Noticing the time when you posted your comment
Uh, I am just kind of a night owl. Most of our team members work out of Redmond, WA, and our distributed members are either on the East or West coast of the US.
Bonus if my previous usage was incorrect and I didn't notice and I end up copying that same mistake again and again!
TypeScript saves me probably 15+ minutes a day of just switching back and forth looking up what parameters are needed.
It is a one time tax to make everything I do more pleasant.
The commenter you are replying to is talking about a function of fixed-arity, with a config object with required props. Which props are required? A Typed language will tell you immediately “for free”.
Most of the popular large JS projects have switched (or are switching) to TypeScript (or Flow for React, though they'd have used TypeScript today). So that supports the argument in favor of TypeScript.
They didn't say most developers had switched, they said most large projects have switched
Heck just getting auto-complete on an object's members.
A few layers of higher order functions / combinators and I don't remember if I have `value` or a `{ value: value }` container (like map vs flatMap). Or which stage of the curry I'm at. Oh right, I'm at foo(a, _, c) but thought I was at foo(a, b, _).
If you can't even remember the last time you've encountered a runtime error, you are by my definition writing trivial code or not writing much code at all.
Static types massively make it easier to understand new code. I can actually see the structure of the data that's getting passed around, with types.
You don't waste time writing tests that simply check if all the arguments received the right type. This is taken care of by the type checker.
Besides, the biggest benefit of types is readability.
Not all static languages give you this but the trend is pretty clear with Typescript, Swift, Kotlin etc.
Fortunately, I work as a team lead, and this was on an experimental branch, so I was able to hand off bits of code relating to architectural patterns I was evaluating to my team to continue work on those.
But I simply could not proceed with my code as is, a very frustrating experience to say the least. How is this even possible?
As a team lead, I'm sure you know...bugs happen. What sort of internal error was it causing? Something specific and spelled out, or a generic uncaught exception?
Error: Debug Failure. at Object.assertDefined (/media/psf/Code/Hypothesize/node_modules/typescript/lib/tsc.js:1690:24) at /media/psf/Code/Hypothesize/node_modules/typescript/lib/tsc.js:13175:89 at String.replace (<anonymous>) at formatStringFromArgs (/media/psf/Code/Hypothesize/node_modules/typescript/lib/tsc.js:13175:21) at Object.createFileDiagnostic (/media/psf/Code/Hypothesize/node_modules/typescript/lib/tsc.js:13191:20) at createDiagnosticForNodeInSourceFile (/media/psf/Code/Hypothesize/node_modules/typescript/lib/tsc.js:7770:19) at Object.createDiagnosticForNode (/media/psf/Code/Hypothesize/node_modules/typescript/lib/tsc.js:7760:16) at handleSymbolAccessibilityError (/media/psf/Code/Hypothesize/node_modules/typescript/lib/tsc.js:71556:50) at checkEntityNameVisibility (/media/psf/Code/Hypothesize/node_modules/typescript/lib/tsc.js:71929:13) at visitDeclarationSubtree (/media/psf/Code/Hypothesize/node_modules/typescript/lib/tsc.js:72066:29)
For example, does the code get compiled using a bundler like webpack? if yes how do you solve the import '../../../../../shared.ts' problem? Or do you use node modules in a monorepo? Compared to other languages I found these questions surprisingly difficult to answer and solutions often quite cumbersome, e.g. if I want to share one small file in my project I don't want to maintain a public npm module for it...
1. https://www.typescriptlang.org/docs/handbook/compiler-option...
We use a single git repo with no npm packages defined, other than the package.json in the root because we have to put dependencies etc. in there. The directory structure for our source code is dead simple:
src/server
src/client
src/common
For example, the API endpoint definitions are common code, so you'll see stuff like this in client code that uses the API: import * as quizApi from "../../common/api/pages/quiz"
The ".."s are annoying, but working around them isn't worth the effort. Even when we heavily reorganize the file organization, it only ends up taking a few minutes to mechanically update these imports with a vim macro, or even with sed if it's a perfectly mechanical change.We run two copies of tsc: one for the client and one for the server, building to build/server and build/client. That results in a weird build directory structure:
src/server/db.js
src/client/app.tsx
src/common/endpoints.ts
build/server/server/db.js
build/server/common/endpoints.ts
build/client/client/app.tsx
build/client/common/endpoints.ts
If you need separate build settings for client and server, this weirdness is going to show up one way or another. However, we only introduced this build separation in the last month or so. For the first 1.5 years of the project, we got away with a single tsc process and tsconfig.json, with no build separation at all between client and server. If anyone who's newer to TS reads this, I'd encourage looking for simple solutions like that; you can get to the weirder stuff down the road if you need it (and you may never need it!)I'm starting to feel behind the curve and I want to learn new stacks like Next.js, Typescript and GraphQL. Anyone else feeling this way or have already gone through that learning curve?
Whether porting existing projects to TypeScript is worth it is of course a question that cannot be answered universally. Depending on how… creative developers were when creating it, it can be incredibly mind-bending.
Yes, sometimes you'll run into weird cases where you have to wrestle the type system, but honestly, in the worst-case you can just ts-ignore those (though you probably want to minimize that).
Next.js and GraphQL are interesting technologies, but I would say they will eventually fade. They do solve some problems, but they introduce new (hard to fix) ones.
Typescript is here to stay. The improvement it brings to the development experience cannot be understated.
It helps the inexperienced to avoid lots of (minor) bugs and providing much more useful autocompletion/inline docs than any javascript analyzer can.
For the experienced people, it is an invaluable tool when the time for largeish refactorings comes. For the first time you can "follow-the-trail-of-errors refactor" in frontend-land.
Type checking did roughly double our build time. Even then, we do run type checking during builds because we prefer the added safety even with this extra time.
Developers run with an incremental checking watcher. It does add a significant tax, and takes a few seconds after saving in some cases (3-4). We would love that delay to go away, but it is a cost we are more than willing to bear if the alternative is not having type checking at all.
I am guessing that Next.js and GraphQL will be long-dead and obsolete "soon" (in the same way that e.g. jQuery & AngularJS were once also red-hot technologies but are now out of favor), but TypeScript really feels like it is here to stay with significant benefits. I guess this is a "learn technologies, not libraries" type thing?
I was "forced" to learn TypeScript for Angular 2 (that was the library of choice at where I worked at the time) but now also use it for my personal stuff out of choice.
Compared to pure JS it is a bit of a pain to get basic development up and running (since you need a TS -> JS compile step before you load it in the browser, unlike raw JS that you can just code and reload). For that I have created myself simple boiler-plate templates (1) that I use to bootstrap a new project so I can be up and running in a browser in 60 seconds etc (the template will do all the compilation and bundling for you using webpack)
Not as safe of course, but you get 90% of the benefits.
If you haven't worked with a statically typed, compile-time type-checked language before, I think you owe it to yourself to learn one, whether or not TypeScript is the one you learn.
Typescript is really just a tool for people who want autocomplete in VSCode for their javascript, or who really still want to be coding in C# and unless you're just dying without those things it's a lot of overhead for not much benefit.
We don't use ts-node for our dev processes because it adds some annoying startup delay. We keep the TS compiler running at all times on our dev machines, and we run our server/tests/etc. from the TS compiler's build output directory. This hasn't been a big pain point for us so I wouldn't worry about it much.
Related, just in case: I definitely wouldn't use ts-node in production. If your deployed code fails to typecheck for some reason, you don't want to learn that by seeing your backend server failing to boot in production. I think you should always compile your app during your deploy process, then have production boot the compiled JS as if TS weren't involved at all.
Besides that, I've never been a Microsoft fanboy(to say the least) and it's worrying me that almost the entire JS eco system falls in the hands of that company; Github, VSCode, Typescript, NPM, etc.. Am I alone in this?
There is so much good stuff in the JS world, but we seem to adhere to a few companies and a few systems more and more. Being a 'Javascript' developer today only has very little to do with Javascript. It's about React, Redux, Hooks, ESLint, Prettier, Typescript, etc.. Oh, and don't forget to do it Agile, another joy and productivity killer. And when you don't agree with this stack you're either not so smart or still need to learn to 'understand' it.
I can only surmise that things are moving in this direction to lower the barrier to entry. As more developers are working with JavaScript it's easier to subscribe to tools to manage consistency than it is to educate and rely on developers' standards to create working efficient code.
Thinking back I've worked on some massive 'Web app' projects over the last 20 years, and the biggest I worked on didn't use much in the way of frameworks or libraries, and standards were maintained by peer review and documentation.
Typescript I suppose automates a lot of this, but I don't think that makes it better.
At the end of the day, they are just tools and how we use them is what really matters.
Lately I have started using FastAPI in Python, which uses Pydantic to enforce type hints at runtime. This saves a lot of manual checking code (e.g. "if input_data["mykey"] == "unhappy path": raise ValidationError").
This was the same annoyance in Node.js because the types are so flimsy and manually checking is really boring. Tests are great but if you can have correctness while rapidly prototyping that would seem to be a win.
Is there a great TS lib to do runtime type reflection like Pydantic?
Typescript in my experience has felt like a collection of hacks more than a well thought out expansion of Javascript. Additionally, it concerns me that official solutions to some problems (e.g. iterating on an enum) require you to write around the code that the compiler will generate. That does not fill me with confidence at all.
As a personal point of contention, I really dislike that the types are useless beyond design-time. But since they don't want to go outside the EMCA spec, we'll likely not see anything like pattern matching on type or type-level destructuring anytime soon.
As it stands, some trivial things can become a nightmare very quickly. Maybe I'm just used to the ease at which ML-family languages can express some concepts.