The most concise explanation of `unknown` vs `any` i know of: - `unknown` is the union of every type there is. - `any` is the "elastic" type which fits to what it needs to be. (It may also be thought of as the switch to selectively disable type checking) bonus point: `never` is the union of no type.
Not using satisfies is barely a Junior Dev mistake. It literally got introduced in the latest release of TypeScript and thus does not yet work in any of my projects. Also obligatory comment about how every youtuber bashes enums because it's the cool things to do and ignores the existence of `const enum` which literally fixes 95% of issues related to enums.
I agree that you don't want to use "any" but if you are a junior dev then you probably don't want to use "unknown" either. Chances are very high that you know what type or types are a possibility at compile time. In this case, instead of returning "unknown[]" the fetch should return "(IAdminUser | IUser)[]" or even just "IUser[]" and then check if the user is admin and cast to admin at that time.
aside from catching errors and writing libraries or packages, I can't think of many scenario's where unknown would be good if you wrote your code properly.
Look, using enums does not make you a junior dev. Enums don't make you anything. And also, yes you can directly pass a number instead of the enum, but that defeats the purpose of enums in the first place. The "junior mistake" is not using enums, but passing the enum value directly instead of using the enum. Do you see the pattern? Using enums is not bad. Using enums the wrong way is bad. I've noticed that a lot of self proclaimed typescript experts on TH-cam talk badly about enums. But that just proves that you are junior devs yourselves. Don't blame a language feature, when you misuse it...
This is a guy who creates a union type and calls it an intersection pipe, so take it with a grain of salt. Enums are bad for other reasons, though: every other feature in TS can be just stripped away because they only exist as compile-time validation. Enums, on the other hand, generate code (an object to perform the map between names and values).
though TypeScript still could improve enums - just passing a number shouldn't be possible. "Don't blame a language feature, when you misuse it..." sounds like C vs Rust, who blames the programmer when does make a mistake that's made easy by the language
ts enum is actually bad compared to other languages, since it doesn't validate type the way you would expect ts or any other compiler to. You should use "object as const" instead of enum in ts because it works more like a proper enum
Too much overhead using enum, it is not possible to generate new enum type out of a old enum type because enum is also a runtime code which is not manipulate able on type level
The "isAdminUser" method should take "IUser", not "unknown". If you are worried that you will not get an IUser from your endpoint, use something like zod.
isAdminUser should take an union type of IUser | IAdminUser and then the type guard can get to work. Using unknown is lazy imho and its not like it will give you any advantage at runtime.
@@Friskni IAdminUser is a subtype of IUser, so "IUser | IAdminUser" is the same as "IUser". I guess the latter is more clear on one hand, but also less clear on the hand, because it makes it look like it is not a subtype.
Great video! The first point at 1:00 does a great job on type guards, but doesn't really explain `any` vs `unknown`. Like at 5:03, code completion has nothing to do with `any` vs `unknown` and everything to do with the type guard. What `unknown` does a great job with is *requiring* that the narrowing happens before assignment. IOW if you change the code to use `any`, it will still work and the type guard will still allow completion. But it will fail to compile if you try to assign the unknown response to a user variable (whether admin or not) before that type guard. Just paste in the following in the typescript playground: interface IUser { id: number; name: string; foo: (s: string) => void; } /** * type guard would be better implemented like stated in the video, using `unknown` type. */ function isUser(obj: any): obj is IUser { // extremely naive checking here for illustrative purposes only if (typeof obj === "object" && typeof obj.name === "string" && typeof obj.id === "number" && typeof obj.foo === 'function') { return true; } else { return false; } } const obj = { id: 42, name: "Alice", foo: (s: string) => { console.log('foo: ' + s); } } obj.foo('const obj'); // compiles because tsc knows of the property on the object itself const anyObjDeserialized: any = JSON.parse(JSON.stringify(obj)); const unknownObjDeserialized: unknown = JSON.parse(JSON.stringify(obj)); // anyObjDeserialized. // no type completion because type `any` // anyObjDeserialized.foo(); // compiles but UNSAFE because we haven't narrowed the deserialized object. // (This actually throws at runtime because you can't deserialize functions like this.) // unknownObjDeserialized. // also no type completion because type `unknown` // unknownObjDeserialized.foo(); // unlike `any`, this SAFELY fails to compile let user: IUser; user = anyObjDeserialized; // compiles UNSAFELY because it's type `any` // user = unknownObjDeserialized; // SAFELY fails to compile, because it hasn't been narrowed if (isUser(obj)) { obj.foo('narrowed const obj') } if (isUser(anyObjDeserialized)) { // anyObjDeserialized. // YES code completion because of type guard anyObjDeserialized.foo('narrowed any'); } else { console.log('type guard worked! deserialized `any` isn\'t a user (because foo fn deserialized isn\'t a function'); } if (isUser(unknownObjDeserialized)) { // unknownObjDeserialized. // YES code completion because of type guard unknownObjDeserialized.foo('narrowed unknown') user = unknownObjDeserialized; // compiles because we have narrowed the unknown with the type guard } else { console.log('type guard worked! deserialized `unknown` isn\'t a user (because foo fn deserialized isn\'t a function'); }
#4 - enums, I understand what your saying about using number enums, but if you misspell one of them and want to rename it, VScode would change it throughout your app. however for "GoodState" and using strings |string |string, if you change the string of the first one, then I don't believe VScode will update the string everywhere.
5:00 - There is no need to actually use 'unknown' in this example, I think it would be more correct to use the following syntax: const goodUser: IUser | IUserAdmin = await response.json() Now you explicitly defined the possible types (interfaces) without being too "generic" with unknown. You can also define an "error" type/interface, let's say "IError", and use a type guard "isIError()". Then: const goodUser: IUser | IUserAdmin | IError = await response.json()
12:49 Fun thing is here, using satisfies keyword along with Record would be a good idea too, because for the red property, without satisfies (so color: Record = {} ) you will only have the common methods/properties between arrays and string, such as .length etc ... I'm pretty sure I saw this exemple in the documentation for satisfied :D
Learnt some new features that Typescript has that I wasn't aware of. The `satisfies` and `obj is Type` sections were nice to see. I've been using Typescript for 4 years, and never knew these existed, though, they may have been added more recently than my knowledge extends to (TS 2.4). I'm currently between jobs, so I'm taking my free time to catch up on technologies that I learnt prior to my most recent job.
1. Understand the "unknown" type in TypeScript to avoid bypassing type checks and compromising code reliability. 2. Avoid using "any" type as it disables TypeScript's type checking, leading to potential errors and decreased code quality. 3. Utilize type guards effectively to determine the type of a variable dynamically, enhancing code readability and reliability. 4. Refrain from relying solely on enums with implicit numbering, as it can lead to ambiguous code and decreased maintainability. 5. Make use of built-in utility types like "Partial" and "Omit" to enhance code clarity and avoid unnecessary complexity in TypeScript development.
Great video, well explained… for all audience, I believe it will be easier to follow the examples if they are very bare or well slimmed down if you’re talking about the basics.
11:04 type on line 18 for enum on line 19. There is cool trick, you can auto generate type for enums. It can be for instance `type GoodStateType = keyof typeof GoodState` - GoodState is enum name
I am not a Typescript fan. I don't hate it but I definitely don't love it. Stuff like this is why. This is all very helpful but that aside from the unknown types and enums most of this doesn't pop up in other tutorials and training. Granted some are recent features but you have to be deep in the weeds of Typescript and frankly I've personally seen no significate benefits using Typescript that's made me want to take such a deep dive. I don't mind learning new things but I was doing fine without it.
Where any is a better choise? I had to use it only in projects with fucked up typings (any everywhere) for solve tasks at estimated time. Enum - yeah, i agree.
@@Vishtar_Official With any, you're essentially opting out of TS. You're saying, I don't want to benefit from TS benefit for this variable. Usually it means you're not understanding a type error message. Better to learn what's going on and keep your code type safe.
@@alastairtheduke That's not what I mean. There are use cases where you don't want to create a hardlink to a specific module by relying on its types for example. There are quite a few of these abstractional situations
Default numbered enums are a nightmare on default. For example, say You have an enums of Status {Accepted, Working, Finished} At that moment Accepted = 0 But if You assign that value like currentStatus = Status.Accepted Then the currentStatus becomes 0, wich is a falsy value and can mess up your logic if you are not paying attention. Enums should be used by default with string values, and numbers only if you really need It. You can also start your enums with 1 as the first value to avoid the falsy value problem
@@marcospenadevYep. And this exactly supports what enums are intended for in 90 percent of cases. Usually enums are used to uniquely identify a type of something. You don’t care it’s value. You just care about a readable unique identifier. Enums also show up differently than constants in most IDEs. There I big readability advantage to visually identify when an enum is being used. Also, enums are easier to work with in type manipulations. It’s rare to run into any issue when using enums. And the argument, “well it compiles to JavaScript blah blah blah anyway” is such a weak reason. That is like someone arguing that you may as well write code in assembly because your code is getting compiled down to it anyway. Today, we write code for humans. Computers don’t need our help reading it.
If you create a good validation function you can use it to detect errors. Suppose the `fetch` call might return either an user or an error message (or the API might change because APIs change).
@@Ctrl_Alt_Elite because it's a bad practice to clean code. It's more efficient to name things like "UserProps", describing the objective of that interface.
I use Types over interfaces because of type utilities and with types you can create something like TUserId = string while you cannot do that with interfaces And I use T as prefix
Enum are good even with numerical values as long as you do 2 things : - Explicitly set the numerical value - Make them "const enum" regardless of the enum being numbers or strings. The satisfies operator is horrible. You should be able to write it as const goodUser: satisfies IUser = { ... } Or at least const goodUser = { ... }
Appreciate the tips and the video. Some constructive criticism: Take a breath once in a while (or don't edit video so it feels like you don't) There really isn't much time for the viewer to absorb your points before you are half way into your next one ;) Otherwise good video. Plenty of self-taught mistake patterns in web-development, nice to know what to look out for :)
What you got there, you said you use for all of your type declarations type MyVar = { myKey: 'myVal', myKey2: 'myVal2' } const myVar: MyVar = { myKey: 'myVal', myKey2: 'myVal2' } Is making you do twice as much work when changes to myVar come. First in type then in object itself. You could nicely avoid it like this const myVar = { myKey: 'myVal', myKey2: 'myVal2' } as const type MyVar = typeof myVar It's the same thing except now you'd work as you normally would with JS objects but with read-only types Please don't bash junior developers with such video titles Happy holidays everyone!
Yes. Infererence over repetition and manual typing. The point of TypeScript is that you want to get the most out of types without explicitly writing them.
The "satisfies" keyword looks really cool. I wonder if it can be used for an implicit cast. The "pass 100 into the enum function" is a thing from a horror. This is C# levels of bad. Does that still happen will all strict modes being turned on?
Hey juniors, if this is you watching, please don't be vocal about this new trend about enums and not using them. These kinds of opinions are only accepted by your peers if they consider you a senior, and won't necessarily win you many brownie points with interviewers. If they bring it up to you, just smile and listen and nod. But don't bring it up since this is honestly a pretty out there quirk and trend. If you establish the contract of the type and then break it by going around it, I'm not going to think the code or the language is bad. I'm going to add a review comment telling you not to do that. It sure is quirky that the compiler doesn't throw an error for such things, but I'm not in the business of tempting fate or acting smart, do I'm not about to lose sleep over this and you probably shouldn't either.
these doesn't necesarily have to be junior mistakes. If you are a generalist, I code in any language that's needed, this might be just due to not having all the language knowledge.
thanks for this video, it was very informative. i don't like the idea of the custom type guard functions, they introduce possible runtime errors since you could write the wrong logic to determine the type, so i think they should be avoided when possible.
great video. would help if you talk slowly or maybe have some transition in between the tips or just maybe pause for two seconds in between. thanks for the video!
I just don't get the hate for enums. It seems people just don't like that they're so dissimilar to enums in the languages they learned before. It's pretty neat that you can use them as a type. Compare: enum Color { WHITE = "white", BLACK = "black" } const color1: Color = Color.WHITE; with: const Color = { WHITE: "white", BLACK: "black" } as const; type Color = "white" | "black"; // Repetititve. An absolute pain to refactor with large objects.
It causes problems when importing them from another package with isolatedModules set in tsconfig. The problem is that only the type gets imported but the values don’t, or at least they’re not available statically, so a lot of inference doesn’t work
The Omit one is great, also yeah, who could be stupid enough to think using numbered enums is good, either you name them with string or don't use them. \
For the pet is cat thing, if Pet was a union type of the classes Cat, Dog, ect. The boolean version would work and tell intellsense that you are dealing with a cat, not a dog, and meow would not throw warnings. Obviously this way works as well l. Just multiple ways to acheive the same result.
I wouldn't really say it's a "mistake that juniors make" by not using `satisfies` when it's such a brand new feature. Don't you think that's a little rude to the seniors? We've done well without satisfies for a long time, and while we _should_ certainly adopt it and use it to better our code further, we shouldn't blame people for not using it already.
The first thing that comes to my mind is "Damn 'I'-prefixed Interfaces again…". A behavior you mostly see in the Microsoft-bubble (C# and MS-inspired C/C++). No one else does it and it's actually distracting when reviewing code since I won't care about the implementation-details here. It's should actually just be a User and Admin/AdminUser! It really doesn't matter it it's a interface, a type or a class but the I-prefix suggests that it's important, although it isn't.
What you refer to as an intersection is in fact a union, so that's a pretty big mistake on someone who is lecturing about mistakes that juniors make...You might want to revise that since a union and an intersection are completely different concepts.
1:16 How is a gender a string? If anything, it should be a boolean array. A boolean array smaller than 64 values can be stored in an integer. I mean, how many possible combinations can there be with 2 different reproductive organs and 1 brain. Seems like a 3*3=9 bit solution to me, LHBTQ is only 5, dunno what the + stands for. At all costs, avoid string comparisons. It's an expesive CPU cycle.
`satisfies` Operator is really an issue as it depict the fact than TS is not so well type checked. I do not understand why a majority of people find this really cool. My feeling is that this keyword is more a patch than a feature.
9:57 I understand now the critics against TypeScript. The language is not intuitive to use. It feels like a patchwork. I understand why MS does this: Backwardcompatibility. There should be a new iteration of typescript that is more intuitve. Like enums are a complete failure and the architects admit themselves they would never do enums that way again. Be open minded for breaking changes!!! But TypeScript is still better than operating without safety at all!
it's a common way to name your type declaration. He used Interface so he named it starting with an I, if he use Type he might use T as the starting alphabet.
Bad habits in my opinion. Prefixing types with "i" for interface is an antipattern in Typescript, it doesn't tell you anything useful. Types and interfaces should be interchangeable and if you have an interface and a class, they should just be give names that naturally make sense.
@@jiitukadu372 All it does is (dis)allow you to declare class properties without giving them a value directly or in the constructor. It has nothing to do with type safety.
The most concise explanation of `unknown` vs `any` i know of:
- `unknown` is the union of every type there is.
- `any` is the "elastic" type which fits to what it needs to be. (It may also be thought of as the switch to selectively disable type checking)
bonus point: `never` is the union of no type.
And when you realize unknown is a complementary type of never
i would add, that use const enum, not enum... it will make optimization better ; )
And what a "no type" would be?
@Winter_Wyvern1are you using it by now?
Not using satisfies is barely a Junior Dev mistake. It literally got introduced in the latest release of TypeScript and thus does not yet work in any of my projects. Also obligatory comment about how every youtuber bashes enums because it's the cool things to do and ignores the existence of `const enum` which literally fixes 95% of issues related to enums.
I agree that you don't want to use "any" but if you are a junior dev then you probably don't want to use "unknown" either. Chances are very high that you know what type or types are a possibility at compile time. In this case, instead of returning "unknown[]" the fetch should return "(IAdminUser | IUser)[]" or even just "IUser[]" and then check if the user is admin and cast to admin at that time.
how about type of error in try catch. Are you use any
aside from catching errors and writing libraries or packages, I can't think of many scenario's where unknown would be good if you wrote your code properly.
@@RmonikMusic If you're using some third party lib or web api you don't particularly trust, it can be a good idea.
Look, using enums does not make you a junior dev.
Enums don't make you anything.
And also, yes you can directly pass a number instead of the enum, but that defeats the purpose of enums in the first place.
The "junior mistake" is not using enums, but passing the enum value directly instead of using the enum.
Do you see the pattern?
Using enums is not bad.
Using enums the wrong way is bad.
I've noticed that a lot of self proclaimed typescript experts on TH-cam talk badly about enums.
But that just proves that you are junior devs yourselves.
Don't blame a language feature, when you misuse it...
This is a guy who creates a union type and calls it an intersection pipe, so take it with a grain of salt.
Enums are bad for other reasons, though: every other feature in TS can be just stripped away because they only exist as compile-time validation. Enums, on the other hand, generate code (an object to perform the map between names and values).
though TypeScript still could improve enums - just passing a number shouldn't be possible.
"Don't blame a language feature, when you misuse it..."
sounds like C vs Rust, who blames the programmer when does make a mistake that's made easy by the language
ts enum is actually bad compared to other languages, since it doesn't validate type the way you would expect ts or any other compiler to. You should use "object as const" instead of enum in ts because it works more like a proper enum
Too much overhead using enum, it is not possible to generate new enum type out of a old enum type because enum is also a runtime code which is not manipulate able on type level
enums should not exist in ts
The "isAdminUser" method should take "IUser", not "unknown". If you are worried that you will not get an IUser from your endpoint, use something like zod.
Or ajv / any other type validator
@@hups6648 I used ajv and moved to zod in typescript context because zod's feature to get type from schema is a game changer for me.
isAdminUser should take an union type of IUser | IAdminUser and then the type guard can get to work. Using unknown is lazy imho and its not like it will give you any advantage at runtime.
@@Friskni IAdminUser is a subtype of IUser, so "IUser | IAdminUser" is the same as "IUser". I guess the latter is more clear on one hand, but also less clear on the hand, because it makes it look like it is not a subtype.
@WyvernABCThats why most of the developer hates js and its libraries.
Great video! The first point at 1:00 does a great job on type guards, but doesn't really explain `any` vs `unknown`. Like at 5:03, code completion has nothing to do with `any` vs `unknown` and everything to do with the type guard. What `unknown` does a great job with is *requiring* that the narrowing happens before assignment. IOW if you change the code to use `any`, it will still work and the type guard will still allow completion. But it will fail to compile if you try to assign the unknown response to a user variable (whether admin or not) before that type guard.
Just paste in the following in the typescript playground:
interface IUser {
id: number;
name: string;
foo: (s: string) => void;
}
/**
* type guard would be better implemented like stated in the video, using `unknown` type.
*/
function isUser(obj: any): obj is IUser {
// extremely naive checking here for illustrative purposes only
if (typeof obj === "object" &&
typeof obj.name === "string" &&
typeof obj.id === "number" &&
typeof obj.foo === 'function') {
return true;
} else {
return false;
}
}
const obj = {
id: 42,
name: "Alice",
foo: (s: string) => { console.log('foo: ' + s); }
}
obj.foo('const obj'); // compiles because tsc knows of the property on the object itself
const anyObjDeserialized: any = JSON.parse(JSON.stringify(obj));
const unknownObjDeserialized: unknown = JSON.parse(JSON.stringify(obj));
// anyObjDeserialized. // no type completion because type `any`
// anyObjDeserialized.foo(); // compiles but UNSAFE because we haven't narrowed the deserialized object.
// (This actually throws at runtime because you can't deserialize functions like this.)
// unknownObjDeserialized. // also no type completion because type `unknown`
// unknownObjDeserialized.foo(); // unlike `any`, this SAFELY fails to compile
let user: IUser;
user = anyObjDeserialized; // compiles UNSAFELY because it's type `any`
// user = unknownObjDeserialized; // SAFELY fails to compile, because it hasn't been narrowed
if (isUser(obj)) {
obj.foo('narrowed const obj')
}
if (isUser(anyObjDeserialized)) {
// anyObjDeserialized. // YES code completion because of type guard
anyObjDeserialized.foo('narrowed any');
} else {
console.log('type guard worked! deserialized `any` isn\'t a user (because foo fn deserialized isn\'t a function');
}
if (isUser(unknownObjDeserialized)) {
// unknownObjDeserialized. // YES code completion because of type guard
unknownObjDeserialized.foo('narrowed unknown')
user = unknownObjDeserialized; // compiles because we have narrowed the unknown with the type guard
} else {
console.log('type guard worked! deserialized `unknown` isn\'t a user (because foo fn deserialized isn\'t a function');
}
#4 - enums, I understand what your saying about using number enums, but if you misspell one of them and want to rename it, VScode would change it throughout your app. however for "GoodState" and using strings |string |string, if you change the string of the first one, then I don't believe VScode will update the string everywhere.
Awesome tips!
I have been working with typescript for few weeks, almost all pf the tips you mentioned I needed them at some point.
5:00 - There is no need to actually use 'unknown' in this example, I think it would be more correct to use the following syntax:
const goodUser: IUser | IUserAdmin = await response.json()
Now you explicitly defined the possible types (interfaces) without being too "generic" with unknown.
You can also define an "error" type/interface, let's say "IError", and use a type guard "isIError()". Then:
const goodUser: IUser | IUserAdmin | IError = await response.json()
Good stuff man. Been in the field for 4 years. Ive only known half of the things u mentioned. Awesome to learn something new today 😄
12:49 Fun thing is here, using satisfies keyword along with Record would be a good idea too, because for the red property, without satisfies (so color: Record = {} ) you will only have the common methods/properties between arrays and string, such as .length etc ...
I'm pretty sure I saw this exemple in the documentation for satisfied :D
title recommendation: "typescript mistakes every junior should make at least once"
Learnt some new features that Typescript has that I wasn't aware of. The `satisfies` and `obj is Type` sections were nice to see. I've been using Typescript for 4 years, and never knew these existed, though, they may have been added more recently than my knowledge extends to (TS 2.4). I'm currently between jobs, so I'm taking my free time to catch up on technologies that I learnt prior to my most recent job.
1. Understand the "unknown" type in TypeScript to avoid bypassing type checks and compromising code reliability.
2. Avoid using "any" type as it disables TypeScript's type checking, leading to potential errors and decreased code quality.
3. Utilize type guards effectively to determine the type of a variable dynamically, enhancing code readability and reliability.
4. Refrain from relying solely on enums with implicit numbering, as it can lead to ambiguous code and decreased maintainability.
5. Make use of built-in utility types like "Partial" and "Omit" to enhance code clarity and avoid unnecessary complexity in TypeScript development.
It's generally agreed not to use Enums, use `as const` objects with indexed type with the same name, export the const and the type from the same file.
All explanations were clearly and consistent, with perfect examples
Great video, well explained… for all audience, I believe it will be easier to follow the examples if they are very bare or well slimmed down if you’re talking about the basics.
I used to make these mistakes 5 years ago. Thanks
11:04 type on line 18 for enum on line 19. There is cool trick, you can auto generate type for enums. It can be for instance `type GoodStateType = keyof typeof GoodState` - GoodState is enum name
I am not a Typescript fan. I don't hate it but I definitely don't love it. Stuff like this is why. This is all very helpful but that aside from the unknown types and enums most of this doesn't pop up in other tutorials and training. Granted some are recent features but you have to be deep in the weeds of Typescript and frankly I've personally seen no significate benefits using Typescript that's made me want to take such a deep dive. I don't mind learning new things but I was doing fine without it.
These are pretty subjective tbh. There are a lot of use cases where any or enums are a better choice.
Where any is a better choise? I had to use it only in projects with fucked up typings (any everywhere) for solve tasks at estimated time.
Enum - yeah, i agree.
@@Vishtar_Official With any, you're essentially opting out of TS. You're saying, I don't want to benefit from TS benefit for this variable. Usually it means you're not understanding a type error message. Better to learn what's going on and keep your code type safe.
@@alastairtheduke That's not what I mean. There are use cases where you don't want to create a hardlink to a specific module by relying on its types for example. There are quite a few of these abstractional situations
Default numbered enums are a nightmare on default. For example, say You have an enums of Status {Accepted, Working, Finished}
At that moment Accepted = 0
But if You assign that value like currentStatus = Status.Accepted
Then the currentStatus becomes 0, wich is a falsy value and can mess up your logic if you are not paying attention.
Enums should be used by default with string values, and numbers only if you really need It. You can also start your enums with 1 as the first value to avoid the falsy value problem
@@marcospenadevYep. And this exactly supports what enums are intended for in 90 percent of cases. Usually enums are used to uniquely identify a type of something. You don’t care it’s value. You just care about a readable unique identifier.
Enums also show up differently than constants in most IDEs. There I big readability advantage to visually identify when an enum is being used.
Also, enums are easier to work with in type manipulations.
It’s rare to run into any issue when using enums. And the argument, “well it compiles to JavaScript blah blah blah anyway” is such a weak reason. That is like someone arguing that you may as well write code in assembly because your code is getting compiled down to it anyway.
Today, we write code for humans. Computers don’t need our help reading it.
Nothing of this makes you a senior dev. It takes so much more
I didn't know the thirs one, super interesting letting typescript to infer the type. Memoizing it😊
This is pure gold. So clear and concise! Thank you!
`satisfies` Operator is indeed awesome. Thank you for the tips, I learned a lot!
4:17 why not assign IUser and then use the isAdminUser to make it more specific?
If you create a good validation function you can use it to detect errors. Suppose the `fetch` call might return either an user or an error message (or the API might change because APIs change).
Thank you so much this tip will adjust my type annotation in correct way to avoid using explicit any type
My recomendation not use "I" prefix to name the interfaces
use "I" prefix to distinguish between interface and class
You should always give a reason lol, that's like saying "you should try to use inference over explicit typing... just cos".
@@CodeOnBlocks watch the video "How to name things in Code" then you'll have an answer
@@Ctrl_Alt_Elite because it's a bad practice to clean code. It's more efficient to name things like "UserProps", describing the objective of that interface.
I use Types over interfaces because of type utilities and with types you can create something like TUserId = string while you cannot do that with interfaces
And I use T as prefix
Enum are good even with numerical values as long as you do 2 things :
- Explicitly set the numerical value
- Make them "const enum" regardless of the enum being numbers or strings.
The satisfies operator is horrible. You should be able to write it as
const goodUser: satisfies IUser = { ... }
Or at least
const goodUser = { ... }
This is great!!! I've been using typescript for a long time and learned something. Thank you!!
Appreciate the tips and the video.
Some constructive criticism: Take a breath once in a while (or don't edit video so it feels like you don't) There really isn't much time for the viewer to absorb your points before you are half way into your next one ;)
Otherwise good video. Plenty of self-taught mistake patterns in web-development, nice to know what to look out for :)
Some tips I knew but would not have been able to explain better than you ! Excellent video.
What you got there, you said you use for all of your type declarations
type MyVar = {
myKey: 'myVal',
myKey2: 'myVal2'
}
const myVar: MyVar = {
myKey: 'myVal',
myKey2: 'myVal2'
}
Is making you do twice as much work when changes to myVar come. First in type then in object itself. You could nicely avoid it like this
const myVar = {
myKey: 'myVal',
myKey2: 'myVal2'
} as const
type MyVar = typeof myVar
It's the same thing except now you'd work as you normally would with JS objects but with read-only types
Please don't bash junior developers with such video titles
Happy holidays everyone!
Yes. Infererence over repetition and manual typing. The point of TypeScript is that you want to get the most out of types without explicitly writing them.
This was great, I learned so much in this video. Thank you!
Nice Tipps 👌
If I'm not totally wrong, you're confusing intersection (& operator) and union (| operator).
Oh that's what I noticed but wasn't sure about !
Simply mean turn of the Typescript "type-checks" "
Someone is junior English ;)
Mate this is so good! Definitely helped out this JS dev!
thanks for this TypeScript tutorial. Love Typescript!
Thanks! Keep up with making videos. They look great!
The "satisfies" keyword looks really cool. I wonder if it can be used for an implicit cast.
The "pass 100 into the enum function" is a thing from a horror. This is C# levels of bad. Does that still happen will all strict modes being turned on?
they fixed it in 5.0 beta
I've been doing all these mistakes. Gonna fix them. Thanks alot.
Hey juniors, if this is you watching, please don't be vocal about this new trend about enums and not using them. These kinds of opinions are only accepted by your peers if they consider you a senior, and won't necessarily win you many brownie points with interviewers. If they bring it up to you, just smile and listen and nod. But don't bring it up since this is honestly a pretty out there quirk and trend.
If you establish the contract of the type and then break it by going around it, I'm not going to think the code or the language is bad. I'm going to add a review comment telling you not to do that. It sure is quirky that the compiler doesn't throw an error for such things, but I'm not in the business of tempting fate or acting smart, do I'm not about to lose sleep over this and you probably shouldn't either.
Excelent video totally understood 'satisfies', utility types and 'is', saved to watch untill I memorize.
these doesn't necesarily have to be junior mistakes. If you are a generalist, I code in any language that's needed, this might be just due to not having all the language knowledge.
thanks for this video, it was very informative. i don't like the idea of the custom type guard functions, they introduce possible runtime errors since you could write the wrong logic to determine the type, so i think they should be avoided when possible.
A better alternative to enums is using a javascript object as const.
I'm super new to TypeScript, but I use all the tips you just mentioned. Does that make me a senior developer?
great video. would help if you talk slowly or maybe have some transition in between the tips or just maybe pause for two seconds in between. thanks for the video!
I just don't get the hate for enums. It seems people just don't like that they're so dissimilar to enums in the languages they learned before. It's pretty neat that you can use them as a type.
Compare:
enum Color {
WHITE = "white",
BLACK = "black"
}
const color1: Color = Color.WHITE;
with:
const Color = {
WHITE: "white",
BLACK: "black"
} as const;
type Color = "white" | "black"; // Repetititve. An absolute pain to refactor with large objects.
It causes problems when importing them from another package with isolatedModules set in tsconfig. The problem is that only the type gets imported but the values don’t, or at least they’re not available statically, so a lot of inference doesn’t work
1:06 that’s why it’s called unknown
😂
thank you. now i know typescript can satisfy Operator
thank you so much
I liked the theme you're using, what is it called ?
Halcyon
Very helpful tips, I've learned a lot. Thanks :)
i loke alot all those tips, also the enum is a good one and the one i most use for strict declarations
Amasing! Thanks for sharing!
You need to slow down, if this tutorial is meant for juniors. You’re talking at 100 mph
Thanks. So much to learn 😊
Great tips, thank you!
Also a best practice is NOT prefixing Interfaces with I...
The Omit one is great, also yeah, who could be stupid enough to think using numbered enums is good, either you name them with string or don't use them.
\
Thank you for sharing those amazing tips. :)
u have kermit accent xD auto subscribe
Very practical tips. Thanks!
For the pet is cat thing, if Pet was a union type of the classes Cat, Dog, ect. The boolean version would work and tell intellsense that you are dealing with a cat, not a dog, and meow would not throw warnings.
Obviously this way works as well l. Just multiple ways to acheive the same result.
superb explenation very clear thanks a lot !
First become a junior to learn the senior ☝
I wouldn't really say it's a "mistake that juniors make" by not using `satisfies` when it's such a brand new feature. Don't you think that's a little rude to the seniors?
We've done well without satisfies for a long time, and while we _should_ certainly adopt it and use it to better our code further, we shouldn't blame people for not using it already.
The first thing that comes to my mind is "Damn 'I'-prefixed Interfaces again…". A behavior you mostly see in the Microsoft-bubble (C# and MS-inspired C/C++). No one else does it and it's actually distracting when reviewing code since I won't care about the implementation-details here. It's should actually just be a User and Admin/AdminUser! It really doesn't matter it it's a interface, a type or a class but the I-prefix suggests that it's important, although it isn't.
Awesome video, thank you!
What you refer to as an intersection is in fact a union, so that's a pretty big mistake on someone who is lecturing about mistakes that juniors make...You might want to revise that since a union and an intersection are completely different concepts.
At the end of the day, the panel who hires you determines if you're junior or senior.
"A huge mistake is not using the `satisfies` operator". Something that exists for about a month. *sigh*
This was really excellent.
That was helpful, thanks
I always forget the is keyword is a thing. My main take away from this video is I need to use the return type : T is R more.
1:16 How is a gender a string? If anything, it should be a boolean array. A boolean array smaller than 64 values can be stored in an integer.
I mean, how many possible combinations can there be with 2 different reproductive organs and 1 brain. Seems like a 3*3=9 bit solution to me, LHBTQ is only 5, dunno what the + stands for.
At all costs, avoid string comparisons. It's an expesive CPU cycle.
I just saw “using Enums” and closed the video
Thank you so much!!
Good stuff!
The I prefix you use with interface is obsolete for quite a while now
Why?
One mistake you didnt avoid was prefixing interfaces with "i" as in IUser...
Why is that a mistake? No wait , don't answer that. You made a mistake when you mistook opinions for facts.
@5:00 is that actually inference or type narrowing?
☝Uhhhhhhhh .. oh title is technically accurate ...
He does show many typescript mistakes you should avoid ...
7:31 it is rather asserting than casting
`satisfies` Operator is really an issue as it depict the fact than TS is not so well type checked. I do not understand why a majority of people find this really cool. My feeling is that this keyword is more a patch than a feature.
11.20 why not to use
Const BetterState = {
Asd:”123”
} as const
Morning with this ❤
const {} as const is preferrred over using enum entirely
9:57 I understand now the critics against TypeScript. The language is not intuitive to use. It feels like a patchwork.
I understand why MS does this: Backwardcompatibility.
There should be a new iteration of typescript that is more intuitve. Like enums are a complete failure and the architects admit themselves they would never do enums that way again. Be open minded for breaking changes!!!
But TypeScript is still better than operating without safety at all!
is there any difference if I change to: function isAdminUser(object: unknown): object is IAdminUser { return Boolean(object?.token); } ?
string | ICustomImage is not types' intersection, it's an union
Hi! Is this VS Code?
What extensions are you using to make it look so good? :D
Yes it is. Its a theme that i wish to know the name as well
Thank you for really useful tips !!
By the way, I just wonder why you named IUser, IAdminUser types intead of just User, AdminUser?
it's a common way to name your type declaration. He used Interface so he named it starting with an I, if he use Type he might use T as the starting alphabet.
@@ngamsomset I got it! Thank you so much😄😄😄
Bad habits in my opinion. Prefixing types with "i" for interface is an antipattern in Typescript, it doesn't tell you anything useful. Types and interfaces should be interchangeable and if you have an interface and a class, they should just be give names that naturally make sense.
thank you, that awesome!
I wish I could know these tips sooner
Thank you so muchhh
"Property has no initializer and is not definitely assigned in the constructor"
i got these error many times, how to resolve these errror?
tsconfig.json -> compilerOptions: strictPropertyInitialization: false
thanks, but "strictPropertyInitialization: false" is needed for type-safe ,
is their any other way...
@@jiitukadu372 All it does is (dis)allow you to declare class properties without giving them a value directly or in the constructor. It has nothing to do with type safety.
What is the theme used in VSC?
Halcyon
I'm a backend developer, why did I watch this?)
real good one!
@CoderOne what is the extension causing the function names to stick to the top when you scroll?