×
Dismiss this pinned window
all 90 comments

[–]BenKhz 142 points143 points  (26 children)

Everyone hates type checking... Until they don't.

[–][deleted] 30 points31 points  (5 children)

Most people I met who are against typing think that it's wasting the the they'd otherwise spend writing the next feature, because whatever problem will occur from assuming the wrong things hasn't yet happened (or rather they're sure that it won't happen), but TypeScript just screams right now "I need to be either a boolean or a null" and they don't like that.

[–]AerieC 31 points32 points  (1 child)

The only devs I've really seen who are strongly against static typing are those who work mainly by themselves on very small projects (e.g. solo web dev).

Almost anyone I've met who has worked on a large project spanning multiple teams of people truly understands the benefits of a static type system.

When you're working by yourself, sure, maybe you can get by without types because you don't have to communicate anything to anyone else, and you don't have to worry about trying to understand the structure of other people's code and integrate with it.

But when you work on one component that interacts with 10 other components from 10 other teams, and you have hundreds of different APIs that you have to integrate with and understand how to call, what the data types are, etc. trying to do any of that without a type system is just chaos.

Types are documentation.

[–]zephyy 13 points14 points  (0 children)

people who hate typing have never experienced the beauty of writing your backend in a different language, generating an OpenAPI spec and then generating a fully typed api client for the frontend

[–]GolemancerVekk 3 points4 points  (2 children)

TypeScript just screams right now "I need to be either a boolean or a null" and they don't like that.

That's the least of my problems with it.

  1. What I dislike most about the way TypeScript is being used (and I do stress that, because it's not about static typing, or about TypeScript itself) is that it tends to be used as an excuse for not writing unit tests and data boundary checks. Language type safety is not a substitute for either, and if it's used under that assumption it will do more harm than good.
  2. The other big issue I have with it is that it's too damn verbose and still keeps growing. It has gone way beyond type hinting for JavaScript. It becomes harder and harder to justify the cognitive overhead and the time spent with mandatory complex hinting of everything in your code and in any connected libraries and modules.

Don't get me wrong, I love to see comprehensive documentation for every last piece of data in the code. But what does it get us in practical terms?

  • Is it used to assist automated QA testing?
  • Is it used to generate JSDoc?
  • Is it used to perform runtime boundary checks (API checks, ORM etc.)?
  • Is it used to enforce runtime type safety?

If the answer to all of the above is "no" then you're spending all this time writing complex type definitions in TS which have no bearing on other systems (database, API etc.), no bearing on the JS code, no bearing on the runtime, on the documentation, on the testing, on anything. It's data masturbation. It may or may not be helpful to another programmer if they bothered to do more than autocomplete with it. But they typically don't give a shit.

Edit: And (3) a more minor issue is that it's too easily misunderstood by people who come from other programming languages. Some languages like Python lend themselves well to the TS paradigm but some languages like Java/C# or PHP don't. Granted, this isn't TS's fault; programmers who come to the JS ecosystem from others should make an effort to learn it properly, and should be helped to do it. There are too many damn people working in frontend and Node without knowing JS, it's ridiculous. But that's not really on TS, it was going on before TS and will keep being a problem long after it's gone.

[–]curious_but_dumb 4 points5 points  (1 child)

One simple argument.

You work in a big team in a corporate env. Your task is to add a logout button to a project that has been under development for 8 months.

Everything is either a factory, a context or a completely decoupled module. You find some objects being passed around the app that might help you.

Does or doesn't the object authUser contain a method for logout? There's no TS, no JSDoc, no comments and it is being created and partially populated in 17 places.

Or how about having a DTO spit out a model and your frontend build failing, because you assumed that relatedPostList is an array of objects instead of a string url.

Since I began using TS I have not seen a whole lot of TypeErrors and ReferenceErrors. In a big or collaborative project, catching bugs outside runtime is a huge benefit.


Plus when you get back to that passion project you started 4 years ago for headless WordPress and suddenly find a fully typed API with complete WordPress interfaces and know for a fact which call will return what kind of objects with what data and their types. That is why we use TypeScript.

[–]GolemancerVekk -2 points-1 points  (0 children)

There's no TS, no JSDoc, no comments and it is being created and partially populated in 17 places.

And probably doesn't have any meaningful unit tests, and no enforcement whatsoever for data coming through APIs and database connections into the code. So in other words the project is a complete mess. But the fact it has type hinting somehow lets you gloss over how much of a mess it is.

Not because it's well written or in any way maintainable, but because the poor bastard who has to add a logout button will stumble across a method in an object that looks like it does a logout a few minutes sooner. Which of course they could've found just the same by grepping for "logout", but because they found it with TS and autocomplete it makes everything better.

Please.

a fully typed API with complete WordPress interfaces and know for a fact which call will return what kind of objects with what data and their types. That is why we use TypeScript.

That is a good use of TypeScript. But no, simply declaring the return types for the API in TS does not let you produce conformat data at runtime. You still need to run code to verify the data against a definition and reject/massage it to make it fit the shape you want.

The problem is that in most projects the definitions (1) for the API interface, (2) for the API data verification, and (3) for the API output to the rest of the code are three different things. Best case scenario is the project uses a framework that does 1+2 together and maintains 3 completely disconnected (with TS). (And then one day some smartass disables 2 because they notice they get a boost of performance that way, and gets away with it because QA are overworked and haven't tested failure paths in six months.)

[–]octatone 37 points38 points  (17 children)

It’s usually until the first time they use a typed language.

[–]zephyrtr 16 points17 points  (2 children)

Theres a learning curve too. Its best to drop new users into a well typed codebasw first and ask them to do simple shit. Once they see all the discovery, they understand the benefits.

But lots of loose typing or any or object? All pain, and they won't know its because of type system WORKAROUNDS, not the type system itself.

[–]Zaemz 2 points3 points  (1 child)

codebasw

I read this as "coleslaw".

type system WORKAROUNDS

Preach. I was just complaining about this in another thread. I've seen quite a few TypeScript projects where there was a very large amount of effort gone into utilizing type inference and avoiding writing any type identifiers. I think explicitly specifying types is a nice part of self-documenting code. Plus, it makes it easier to look up the type's definition.

[–]zephyrtr 1 point2 points  (0 children)

Agreed. Type inference is great, but being explicit means you can't accidentally change the return type. I see that happen a lot where over time the types have shifted. Suddenly nullish, etc.

[–]Doomguy3003 10 points11 points  (3 children)

Literally me turning from JS to TS. My first two jobs used JS and PHP - both not statically typed. And I did fine, so when I was looking at TS, I thought it's so uselessly verbose and it's just not worth it. Now that I've started using it for more than one project, having types is so nice.

[–]webstackbuilder 3 points4 points  (2 children)

I think PHP's optional static typing is the norm these days. Laravel (an MVC framework based on Rails) had a lot to do with that.

[–]Zaemz 2 points3 points  (1 child)

Isn't Laravel a Symfony project? Or do you mean that it's based on Rails as a style?

[–]webstackbuilder 0 points1 point  (0 children)

Laravel's not a Symfony project. It used a number of Symfony modules in its earlier versions, but most of them have now been replaced with the project's own versions. The framework is heavily patterned on Rails in its architecture.

[–]dillydadally 1 point2 points  (0 children)

Started my career with C/C++ many years ago when C++ was a lot less developed. I can confirm I hated type checking after that and PHP was a breath of fresh air. Then PHP was evil. Then I tried PHP again recently after they added a bunch to the language and it was really nice. 🤷‍♂️ All I know is I never know enough!

I still prefer dynamic typed languages though if I'm working solo, but I tend to write pretty clean code and very rarely hit type errors.

[–]Aewawa -4 points-3 points  (8 children)

Nope, I still don't like Java

[–]fireball_jones 4 points5 points  (7 children)

There's a massive difference between adding types to JS and Java.

[–]Aewawa 1 point2 points  (2 children)

Yeah, but the comment was saying "typed language" not TypeScript. And that is the first typed language of many people, in fact, it is the first language of many people along with C/C++.

And back in the day a lot of people were escaping those languages to work with Ruby.

[–]fireball_jones 2 points3 points  (1 child)

Sure, but there's a difference between not liking types and preferring a language that isn't miserable to work with.

[–]Masterflitzer -2 points-1 points  (0 children)

well on that front, JS and Java are both miserable to work with

[–]dillydadally 0 points1 point  (3 children)

True, but that's not really relevant to the "It’s usually until the first time they use a typed language." Java is a typed language.

[–]GolemancerVekk 0 points1 point  (2 children)

They're all typed languages. You have to qualify it with dynamic/static and weak/strong and other clarifications regarding type safety and explicit/implicit type conversions.

[–]dillydadally 0 points1 point  (1 child)

You're right. I'm just speaking casually.

[–]dillydadally 0 points1 point  (0 children)

You're right. I'm just speaking casually along with the current conversation. When the original comment said typed language he was talking about a statically typed language I believe. Otherwise his comment doesn't really make sense.

[–]_PC__LOAD__LETTER_ 3 points4 points  (0 children)

Until they love it, more specifically. For me it went some right like: hate hate hate hate love

[–]lifeeraser 1 point2 points  (0 children)

Statically typed languages with anemic type manipulation capabilities (e.g. old Java, old C++) can make you believe that typed languages are inflexible in general. TypeScript helped me realize how powerful static types can be.

[–]had_a_beast 85 points86 points  (6 children)

Awesome, thanks for the video. I have a question. Why should I ever use anything other than satisfies ever again?

[–]ghillerd 29 points30 points  (2 children)

I'm not 100% sure, but it seems to treat the object similar to as const, so if your object is mutable or has programmatically generated keys you might be better of with a regular type declaration.

[–]mypetocean 14 points15 points  (1 child)

If you want to signal that the object should be treated as immutable, I think you still want to use it:

as const satisfies

In the previous example posted by Steve, the video shows a use-case for wanting both.

[–]ghillerd 1 point2 points  (0 children)

Great example, thank you! This is new syntax to me. I'll have to dig a bit deeper into exactly how this works.

[–]FridgesArePeopleToo 8 points9 points  (1 child)

for one, you can't add or change your object after it's declaration like you could with a standard Record<> eg: record["something"] = "blahblah"; wouldn't work. Or if you had a type with a union like

 type Test = {u:"a" | "b"} 
 const o = {u:"a"} satisfies Test 
 o.u="b" //doesn't work

[–]Mkep 0 points1 point  (0 children)

This is unexpected to me; thanks

[–]steve8708webdev talking head dude[S] 46 points47 points  (0 children)

Note: the satisfies operator is available since TypeScript version 4.9.

Thank you all for the feedback on my last video to include a more real world example of when exactly you should use this operator.

And huge thanks to u/sauland for this routes example to nicely illustrate this feature.

[–]FoolHooligan 48 points49 points  (5 children)

Seems like satisfies does what the type declaration should've done in the first place. Like I guess that elsewhere you could mutate this object. Does satisfies just assume that the object is "frozen"? Interesting to see if we can mutate this object outside of the original declaration.

[–]FridgesArePeopleToo 10 points11 points  (1 child)

You can mutate the object, but you can't outside of the bounds of the declared obj. Like in this Record<,> example, you can't add new keys to it after you declare it. If you use satisfies on a Union type, you can't change the value to be a different value that matches one of the Union values.

[–]FoolHooligan 2 points3 points  (0 children)

I should've said mutate its structure. That makes sense. Alternatively I suppose you could enumerate the first generic argument of the Record, like Record<"someKey" | "someOtherKey", string>, but this satisfies operator is much more elegant and less verbose. Pretty awesome.

[–]NoInkling 4 points5 points  (1 child)

It's the same as if you don't use satisfies, you get the inferred type. All satisifies does is surface errors at the declaration, other than that the provided type is "forgotten".

If you want the benefits of both inference and the indexed type, you can use an intersection type, for example:

const mutableRoutes: typeof routes & Routes = routes

Maybe that's something that could be made more ergonomic in the future.

[–]FoolHooligan 0 points1 point  (0 children)

If you want the benefits of both inference and the indexed type, you can use an intersection type

This is very interesting. Could you provide a more complete example?

[–][deleted] 2 points3 points  (0 children)

I think so, the object becomes frozen. Once you can mutate it you can also delete keys and then assuming certain keys are there become invalid.

[–]Turd_King 28 points29 points  (1 child)

Jesus Christ man, Typescript really is a mess of a language. How many key words are they gonna add before they are satisfied

Disclaimer: I use TS every day and have done for 6 years.

[–]hmaddocks 7 points8 points  (0 children)

This is what happens when there is no definition of done.

[–]Stutterboy22 9 points10 points  (3 children)

u/steve8708 what software do you use for the screen recording and the speech transcription?

[–]steve8708webdev talking head dude[S] 5 points6 points  (0 children)

I use Descript for everything - recording, editing, and captions. Makes for a very fast workflow

[–]aschmelyunphp / js / docker 1 point2 points  (0 children)

Would also like to know this!

[–]Not_a_spambot 0 points1 point  (0 children)

Not OP but the recording part at least is probably OBS

[–]moose51789 2 points3 points  (0 children)

Nifty!

[–]artbyiain 2 points3 points  (0 children)

What’s the benefit of Record? i would have written that type as {[key:string]: Route}, which allows for autocomplete.

[–]ShawnyMcKnight 7 points8 points  (9 children)

I don't know why but Typescript has been a challenge to me. I watch videos like this and it's difficult to not only conceptualize what is happening but then to retain it for future use. I've been watching videos on Typescript Generics over the past few days and still struggle with understanding how they are better. It seems like they are an alternative to using 'any'.

I think instead of watching videos I should try to code stuff out more. After I finish the LinkedIn Learning video series I am on for Typescript I'll probably see if the typescript docs page has a tutorial.

[–]Affectionate-Set4208 10 points11 points  (1 child)

Yes, you should start coding asap. That helps a lot in retaining info. Just watching a video, for the majority of people, is not enough to remember much info

In this case, I got what satisfies does, since I have suffered many times what he shows at the beggining. Sometimes when you tell typescript that a variable x is of type Y, then you loose the exact declaration of what it contains. (say for example Y.a is optional, then now you don't know if your variable x has that property or not)

And finally, what doesn't help either is that he uses an utility type

[–]ShawnyMcKnight 1 point2 points  (0 children)

Thanks for the tip! I tried just using typescript when I made a new react project and I was getting the very basics of declaring types when I declared a variable, but I was getting really confused when I had to bring in a JSON file. It was a somewhat complex one with lots of nested pieces and I was getting confused trying to declare types for it all.

I'll get back to it eventually but it's hard to do when there is no pressing reason to learn it. It is just on some of the job applications I fill out so I come back to it when one of those prospects gains traction.

[–]FridgesArePeopleToo 1 point2 points  (0 children)

The most obvious example of Generics being better is arrays.

type Test : {a:string,b:number}
const testArray : Test[] = [{a:"A",b:10}]
testArray.filter((item) => item.a === "A");  //now I have autocomplete on item!

[–]r0ck0 1 point2 points  (0 children)

I think instead of watching videos I should try to code stuff out more.

Yep. Very hard to learn and retain programming stuff passively.

Videos are fine when you're eating or in bed or whatever. But if you're actually sitting at your computer, learn by doing.

Here's what I suggest:

  • Make yourself a project named something like typescript-learning or typescript-experiments
  • Set your editor up with a shortcut key to run the currently open file with ts-node

Then each time you're learning about a new feature:

  • Make a new file, with the date and feature name, like 2023-01-07_satisfies.ts
  • Do some tinkering.

Benefits:

  • a) Better learning
  • b) Better retention
  • c) Something to look back on quickly, with examples that make the most sense, because you picked them

I do this for every programming language I want to try out. And also stuff like experimenting with git.

Sometimes I go back to these projects years later, and I pick the skills up again really quickly because of (c) above.

The thing with all learning materials (video/books/web/everything) produced by other people, is that they're full of a combination of both:

  • Stuff we already know
  • Stuff we don't know

Therefore it's time consuming to jump to the bits we need a fill-in on. Whereas when you create your own little files that contain nothing but the new bits you're learning, there's nothing else to wade through. Only the stuff that was new/novel to you at the time. The rest is probably already in your head.

[–]SoulSkrix 0 points1 point  (2 children)

Make a list of things you want to learn about typescript, and then during one of your coding sessions (don’t be a perpetual student and just looking at training material all the time.. learn a lot slower that way), simply try to find a good use case for one and use it. You’ll learn only by applying your knowledge, which is scary and messy, but it’s the best way

[–]ShawnyMcKnight 0 points1 point  (1 child)

Thanks! My next thing I want to learn is VueJs and I figure I will create it using typescript. Most likely all I will do in it is make some custom types, but who knows?

I tried it with a portfolio I made in react for class but time was too short and I had to revert back to JS. The main issue I had was I knew NOTHING about typescript at the time and never created a react project. So I was trying to ask questions and was only finding JS examples, which then I applied and the TS linter was being super strict on me.

Now that I have more time I can mess around more with it when I make a Vue project. I figured I could use the Pokemon API to make my own Pokedex and after I finish that maybe turn it into a store where you buy pokemon, no backend at all, just set it up. I have a problem where my work doesn't use a JS framework so I don't really have much to show in that regard.

[–]SoulSkrix 0 points1 point  (0 children)

That certainly sounds like a nice project idea for learning a framework.

As for your TS issues, Typescript is designed to be adopted over time. That is, you can just write JavaScript and only add typescript where you are comfortable with it for now. You can also look into the tsconfig.json and change settings to make it less strict for you. I recommend just trying to declare types for data (like a JSON object that represents a Pokédex entry) and function parameter types and return types. With just those 2 changes you’ll have a lot of nice inference for little effort

[–]Gwolf4 6 points7 points  (1 child)

So the original type checking for TS was "incomplete", that is what I am getting, am I right?

[–]Turd_King 1 point2 points  (0 children)

Yes essentially

[–]ethansidentifiable 3 points4 points  (0 children)

I loved sauland's example and I think going back and redoing this was a great idea! I hope more people get the value of satisfies with this video! 😃

[–]salvan13 1 point2 points  (0 children)

I am confused, what's the differences? When to use which option?

[–][deleted] 1 point2 points  (0 children)

neat! thanks for sharing

[–]Noch_ein_Kamel 0 points1 point  (3 children)

So what confuses me...

At 0:29 the autocomplete(?) shows "AUTH.path" and at 0:32 the editor clearly states: "Error: Property 'ATH' does not exist"; the Editor apparently already knows what properties are allowed.

So why do I need "satisfies"?

[–]selectra72 0 points1 point  (1 child)

It wasn't editor auto complete, it was github copilot autocomplete

[–]Noch_ein_Kamel 8 points9 points  (0 children)

Oh okay. He probably should disable that for such videos.

[–]betterdaz3 0 points1 point  (0 children)

That is GitHub Copilot, not the editor itself.

[–]dingus-the-white 0 points1 point  (0 children)

I really need to start reading typescript release notes, this is awesome

[–]ExistingBug1642 0 points1 point  (0 children)

who is that guy?

[–]Puzzleheaded_Toe117 0 points1 point  (0 children)

Unnecessary garbage

[–]3ssencex0 0 points1 point  (0 children)

Puică, ce faci aici ?

[–]RebelColors 0 points1 point  (0 children)

This is really cool, I’m definitely going to try it. Thanks for sharing.

[–]kingdomcome50 0 points1 point  (0 children)

The title here doesn't make any sense. I don't see a "use case" here; nothing is being used. Idk about you guys, but the features I push are more than simply defining a variable and then hovering over it in my editor...

If we were to extend the example in the video to exemplify how one might use the routes variable, we would clearly see how as satisfies doesn't contribute anything additional to type safety or editor support:

``` const routes = { AUTH: { path: "/auth", }, } as const;

routes.AUTH.path; // "/auth"

declare function useRoutes(routes: Routes);

useRoutes(routes); // only accepts a value that "satisfies" Routes. ```

This new syntax feels like it's trying to shoehorn more nominal typing into a structural type system. All for the sake of allowing those unfamiliar with how TS works to "feel better" about the code. Pass.

[–]Apprehensive_Ad_8227 0 points1 point  (0 children)

It was never a 'killer feature'. It could have been done easily before.

`function literal<U>() { return <T extends U>(value: T) => value }`