The biggest issue I've had with 'as const' is that it doesn't play well with libraries. Because of the readonly you'll get into cases where libraries are expected something like string[] and will require casting to mask the readonly. It also doesn't actually freeze the values, which can cause hard to debug bugs
I'm getting kinda imposter syndrome, please explain if we really use such tricky advanced concepts in coding, or is it okay if I'm using simple intermediate level code to get my stuff done, without engaging in fancy stuff like this. Btw, amazing video 🔥🔥!!
Like everything: It really depends. If you’re not a library developer but a consumer of libraries, and you’re able to develop comfortably without leaving much bugs in the code then you’re good. If you _do_ often encounter bugs _OR_ if you want to continue growing as a programmer (which I assume is what you’d want) it’s wise to learn these concepts so you’re prepared in the less common cases where you run into them, or so you have a broader background to make better decisions.
this i cool and all. but its actually just a workaround for an anti pattern., in the example case u give, why are u not using an enum type on routes, if fixed values are used ?
Enums are considered harmful. Matt has another video on the topic, but in short, there are a bunch of design flaws that can cause some unexpected issues at runtime without raising an error when type-checking. They’ve been improved a bit in 5.0, but still have some sneaky footguns
Metadata based programming can be very very powerful. It essentially allows you to expand an application by just adding metadata to an object, while also writing less code overall. I have found that old codebasis often have similar and/or duplicate code all over the place, which can be refactored with this metadata based driven approach. Cuts down on TONS of boilerplate.
Thanks a lot for this longer explanation! I sometimes have a harder time catching up on the really short videos but here I was able to get everything immediately.
Great... now I have to clean my walls.... you HAD to blow my mind didn't you Matt? sigh... Feedback: at 5:20, you video recommendation thumbnail is covering the code you are still explaining, maybe make an outro?
Excellent video! You often make videos about bleeding edge TS features (that I can’t use yet) or incredibly complex topics (that make me scratch my head) but this video was super accessible and easy to follow! Here’s hoping you will make more mid-level TS concepts videos.
Why didnt you use enums for the routes? It looks like you only need one of the three routes at any moment. This particular example doesn't show use of as const i think. (I'm new to typescript so maybe I'm wrong, please correct me)
Right, why prefer the code in the video in place of a string enum? String enums are made for this, and they generate faster and generally smaller JS output. const enum Routes { Home = "/", Admin = "/admin", Users = "/users", }
@@programming5274 I totally agree yet I supose it is just to show that we have that option too. Imho u end with objects from other devs everytime so maybe u can just put 'as const' on them instead of refactoring to enums other people's job, idk
The most underrated in TypeScript is *YOU* haha just kidding you can get tell you are respected by the way everyone else are referring to the wizard 🎉🎉🎉🎉
It would, but Matt has an irrational hatred for them, as seen in one of his videos "Why you shouldn't use Enums". Watch him abuse the concept of Enums and instead using magic variables. Biggest tool I've seen in TS.
Because, if you read the comments here, using Enums is bad for reasons most don't understand or are not impacted by in actuality. This hacky, non-intuitive solutions to a very basic problem is somehow superior, because... Well. It isn't. Glad this video doesn't disappoint, because Matt is such a massive tool. Simply look up his "Why you shouldn't use Enums" and waste minutes of your life watching a man glorify magic variables via transitive property instead of seeing Enums as what they are.
Hi Matt, I'm wondering if this prettify option could/should be better or not: export type ValueOf = Prettify; type Prettify = { [K in keyof T]: T[K]; } & {};
Thanks man, 3 months ago I started learning expo, and I wanted to make routes, I suffered so much because of that, I was obligated to type routes as any...and now I know how to fix it❤
const obj = { username: 'abc', password: 'dce', email: 'fgh', } as const; let a: (typeof obj)[keyof typeof obj]; // Value of an object let b: Exclude; // Exclude a value from an object let c: keyof typeof obj; // Keys of an object let d: Exclude; // Exclude a key from an object
is there a shorthand for this syntax (typeof variable)[keyof typeof variable]? just curious because it's this is going to be used a lot in the code base.
I don't get to just use typescript at work, but I sure as hell use jsdoc to the fullest in the meantime and love getting to do similar things with types. When you know for sure that you'll get auto completion and type errors, it's amazing how much less code you can end up writing. I recently set types up in such a way that I could safely turn 1000+ lines of manual references to properties on an object into just a few lines of code that auto updates, types and all.
The thing about 'as const', when not used on type parameters, is that it lies. The runtime object is, in fact, not readonly. You can get the same effect, with added runtime correctness, from Object.freeze. I consider this an extension of the 'One Source of Truth' ethos. 'as const' is, essentially, a type assertion. But I'm %100 guilty of using it everywhere so 🤷
yeah and now pass this back into the library so the link maker function can be part of the library. And make it so the handlers and routes can be defined in one spot so we have a single source of truth. not possible, because it is a circle. I just want typescript for the autocomplete, but getting more extreme about it does not solve the issues I try to solve. maybe a custom vs code plugin / language server will do better than going deeper into this maze. There is value in typescript. But you have to know its limitations. otherwise you get stuck in a maze and forget that its original purpose was to make you more productive so you can deliver something for your users.
I don’t understand the reason for all this. In such situations, you use enums which can also be used as expected interfaces within your function arguments.
It is really ridiculous that we are used to something like const name = { ... } as const; If there was a new language that would propose something like this it would be laugh at till the end of times, and yet here we are, we all are using language like this. But aside from that you could do a helper type like this: type ValueOf = T[keyof T];
Nice video! Heads up on this format on mobile because there's no RU-vid outro, the "suggested video" card appeared whilst you were still coding and blocked the code in video
As someone who doesn't know TS and just knows C#, I recoiled slightly when I saw the keyof typeof [] bit But then I remembered reflection is pretty much like that anyways in C#, accessing public (or private) members and the like.
The difference is that reflection happens at runtime. This "as const" typing happens statically at compile time, so it's typesafe -- unlike reflection. On the other hand, typescript types are not reified, whereas .net types are. So reflection over typescript types isn't possible, because the type information is erased during compilation.
Another trick is `as const` objects somewhat work with built-in methods while almost not losing all type info: ```typescript const ROUTES = { home: "/", admin: "/admin", users: "/users" } as const; // sadly not a tuple of literals, merely an array of literal type union const routeValues = Object.values(ROUTES).map((value) => value); export type IRoute = (typeof routeValues)[number]; export function validateRouteValue(inputValue: unknown): inputValue is IRoute { // have to coerse type there because typescript is iffy with `Array.includes()` // when it's array of string literals return routeValues.includes(inputValue as IRoute); } export function doSomethingFromValue(inputValue: IRoute): void { switch (inputValue) { case "/": case "/admin": case "/users": { break; } default: { throw new Error(`Invalid value "${inputValue satisfies never}"`) } } } ``` Achieves the same result but you also get a validation function which acts as a type predicate. The `doSomethingFromValue()` also shows how literal type unions can be paired with `satisfies` keyword to achieve exhaustive switch cases.