Intermediate TypeScript, v2

Intermediate TypeScript, v2 Ternary Operators & Expressing Conditions

Learning Paths:
Topics:
Check out a free preview of the full Intermediate TypeScript, v2 course:
The "Ternary Operators & Expressing Conditions" Lesson is part of the full, Intermediate TypeScript, v2 course featured in this preview video. Here's what you'd learn in this lesson:

Mike introduces conditional types as a way to express type information similar to a ternary operator. How to define a conditional type that evaluates to different types based on a condition, and examples of using conditional types with literal types and union types are also covered in this segment.

Get Unlimited Access Now

Transcript from the "Ternary Operators & Expressing Conditions" Lesson

[00:00:00]
>> Next, let's take a look at conditional types. You can think of conditional types as kind of a ternary operator, but for type information and just so everybody understands what I mean by the ternary operator. It's this where we could say shorthand for if then else. If x is greater than 0, then the expression should evaluate to no.

[00:00:26] Otherwise, it should evaluate to yes. So I imagine a lot of you have seen this. This is part of modern JavaScript has been around for a while. So let's look at the type equivalent to a ternary operator. We've got two cooking appliances, a grill and an oven. And I can define a type cooking device that's generic over T, a type param.

[00:01:01] And if T extends the string literal type grill, evaluate to a grill. Otherwise, evaluate to an oven and look at what we get. Device1, grill. Device2, oven. It's a little bit of if--then-else happening here. And remember my argument for extends being like, is subtype of? You can think of it as in terms of this condition, you're evaluating whether T is a subtype of grill.

[00:01:49] In this case, it's a unit type. It can really only be grill and you might witness that even if we screw this up, we're gonna end up with oven because anything that doesn't match grill is regarded as an oven. That's just how these work same as if I were to screw this up sort of like if the conditions not met, absolutely everything else flows through and you get the if condition not met expression as what you evaluate out to.

[00:02:22] These are some interesting examples. So we've got some values 1, 2 and 10 because these are const declarations. And because the value we assign to these variables, they're immutable values. Numbers cannot be altered once. Once declared, these end up being literal types. It comes ten is of type ten, there's only one thing this could be.

[00:02:46] So we could create some interesting types here. So this one is like is low number and we're saying, okay, if T extends one or two, then is low number should evaluate to true. Otherwise, it should be false. And if we look, TestOne is true. TestTwo is true. TestThree with TestTen is false and look at this, TestTen with two.

[00:03:23] We're passing a union type through this type param. That's interesting, we're getting Boolean out. We don't have Boolean anywhere in our conditional type. I mean, we have true and false, but that's interesting. There's a question that I see, does grill and oven being lowercase when passing in the type parameter matter?

[00:03:48] Is there is there case sensitivity. So there is case sensitivity and the only thing that you have to do is make sure you match. So if we did capital G for grill, this is gonna turn into oven. Just think about it like a string comparison check, you can fix that by doing this and you'd be okay.

[00:04:06] In either case, they are different strings held in different places in memory, but those strings are not equal to each other, unless they're case-sensitive. Yeah, the strings don't have to be class names here, we'll do that. Really, it's just comparing this cuz this is the T, right, cooking device.

[00:04:31] If I hover over this, see how it's like T extends G. So it's just G coming through here. It It is not really connected with the class name at all. Okay, let's go back to this puzzling thing here. Does anyone have a theory as to why we're seeing this?

[00:04:53]
>> It knows its load number just resolves to Boolean.
>> IsLowNumber does resolve to a Boolean, why?
>> So it's the only options coming out of the ternary. It could be either or, or false.
>> Could be either or, one of those evaluates to true. The other one evaluates to false and you put those together and you get Boolean.

[00:05:24] What we're seeing here is evidence that when we project a union type through a type parameter, you really wanna think of that as if we did this. It's the same thing. When you project a union type through a type parameter, you wanna imagine as if every element of that union type is individually evaluated and then we take all of those results and we union them all together.

[00:06:06] That's why we're getting true, it's both. Jay asks, is T always the top level type? This is just cargo culting. If you wanna look up that term, it's a convention that doesn't have any particular importance or value. But in C++, the equivalent concept to this was called template classes where you could take in a type param just we're doing here or capital T for template and it has stuck.

[00:06:45] You'll see that in Java and C Sharp anywhere they're type params people use capital letters. You can do whatever you want. As long as you match the number off these, you're fine. These you can name however you want. There is a convention around using at least capitalized things, but I would just say that is as important as beginning variable names with lowercase and beginning class names with capital letters.

[00:07:20] The value is in us being able to look at something and to sort of understand what it could be and what it couldn't be. But beyond that, there's nothing that would stop me from doing this. It can be whatever you want.