In JavaScript, some values of different types are considered “falsy”, which means if you were to cast the value into a Boolean using two NOT operators or with the Boolean() built-in function, it would become false, where every other value would become true.
2. Number
Numbers in JavaScript are stored as floats, which means you use the same type for whole integers and decimals. JavaScript also has values for Infinity, -Infinity, and NaN, or “Not a Number”.
3. BigInt
very large integers
4. String
5. Symbol
unique and immutable
6. undefined & null
undefined represents uninitialized. null represents the absence of value.
JavaScript also has structural types, which means we can construct different shapes of the primitive types to represent more complex data structures.
Object
All of the other types we’ve looked at so far can be directly compared by value, but objects (and object-like values) are compared by reference. This means two objects that have the same shape aren’t considered equal.
Array
Arrays store data, but use Numbers instead of Strings for indexing properties. This means that the data stored in Arrays is ordered.
Function
Classes
Special TypeScript Types
any and unknown types
any gives you the greatest flexibility, but absolutely no type safety, so it’s best to avoid any unless it is absolutely necessary.
we can convince TypeScript that an unknown or any value actually has a more specific type by using a process called type narrowing. This involves doing runtime checks which either prove that a value is a specific type or prove that it is not a specific type.
As a general rule of thumb, prefer unknown over any and use type narrowing to determine a more accurate type.
Interfaces
Indexable Types
We can mix index signatures with regular property signatures, so long as the key and value types match.
Enums
Notice that we are able to use Seasons as both a type and a value.
Tuple
Tuples are fixed-length arrays. We can tell TypeScript how many items are in the array, and what the type of each item is.
TypeScript will never infer an array of items to be a tuple, even if the items are of different types.
Void and Never
void
void represents the absence of any type. It’s often used to indicate that a function doesn’t return anything.
never
never represents a value that can never occur. If we every try to access or modify a never variable, TypeScript will give us a warning.
type aliases
Interface or type?
Interfaces support extension using the extends keyword, which allows an Interface to adopt all of the properties of another Interface. Because of this, Interfaces are most useful when you have hierarchies of type annotations, with one extending from another.
type aliases, on the other hand, can represent any type, including functions and Interfaces!
Union Types
Intersection Types
Combining primitives will always yield a never type or a type that is impossible to satisfy.
Literal Types
Classes
Class Definition
Class Modifiers
The three class modifiers are public, private, and protected.
readonly is another modifier which is not limited to classes. You can think of this as the const variable declaration, but for object properties.
Property Shorthand
TypeScript gives us a shorthand when our constructor parameters are the same as our properties.
Accessors (get and set)
Notice that I store the name on a different property. If I were to try mutating this.name within my set name() method, it would call set name() again, creating an infinite recursive function.
ES Private Fields
private or #private?
ES Private Fields provide “hard privacy”, which means an outside viewer can’t see those properties even if they wanted to.
As a rule of thumb, ES Private fields are generally what you want to use. However, if you can’t target ES Next when you compile your code, or if you can’t afford to have a lot of polyfill code, TypeScript’s private modifier is a good alternative.
Advanced TypeScript Types
TypeScript Operators
Type Indexed Access
typeof
const assertions
Type Narrowing
Common Type Guards
Primitive types
Arrays
Classes
instanceof operator
Objects
Using object instead of unknown will tell TypeScript to let us attempt to access properties on this value. We can create a Union of the generic object type and an Interface with the property that we want to access.
Handling null and undefined
Optional Chaining
?.
Optional Chaining only fails if the property is null or undefined; falsy values like 0 and false will pass through correctly.
Nullish Coalescing
?? - only checks if a value is null or undefined.
|| - checks against falsy values, not just null and undefined.
Non-null Assertion
!.
Assertion Signatures
keyword as
Structural vs Nominal Typing
If we didn’t have the type properties, our Apple and Banana types would be indistinguishable, since they all would share the same property: name:string.
All three of these types are equivalent in TypeScript.
Other programming languages, like Java and C# use a nominal type system. The word “nominal” refers to the name of the thing, which means if I were to create two classes with an identical structure, but different names, those two classes would be considered different.
We can emulate nominal typing by adding a unique property to our types with a string literal type. This practice is called “branding”, or “tagging”, and is what allowed us to differentiate between the two types in the type system.
We can also create what are called “branded primitives”. This allows us to create primitive values which are only assignable to variables and parameters that match a specific type signature.