TypeScript- the love child of C# and JavaScript which you should be proud of and show off to your family.
Topics
π keyof
π Access Modifiers
β‘ static
π Type Guards (User-defined)
π Partial
β Pick & Omit
π keyof
This one does what it says on the tin. It gets the keys of an interface, type or object.
interface MyType {
id: number;
category: number;
name: string;
}
function getProperty<T>(item: T, key: keyof T) {
// more code goes here
}
// const item: MyType = { ... }
getProperty(item, 'id') // Valid
getProperty(item, 'other') // Error
π Access Modifiers
Access modifiers allow us to close down (or open up) access to properties on a class.
private: Only accessible within the class it was defined in.
protected: Accessible within the class it was defined in & any classes inheriting from it.
public: Accessible from anywhere.
class BaseClass {
private privateProperty: string;
protected protectedProperty: string;
public publicProperty: string; // default is public, can be omitted
constructor(
privateProperty: string,
protectedProperty: string,
publicProperty: string
) {
this.privateProperty = privateProperty;
this.protectedProperty = protectedProperty;
this.publicProperty = publicProperty;
}
baseMethod() {
console.log(this.privateProperty); // Valid
console.log(this.protectedProperty); // Valid
console.log(this.publicProperty); // Valid
}
}
class ParentClass extends BaseClass {
methodA() {
console.log(this.privateProperty); // Invalid
console.log(this.protectedProperty); // Valid
console.log(this.publicProperty); // Valid
}
}
let item = new ParentClass("private", "protected", "public");
console.log(item.privateProperty); // Invalid
console.log(item.protectedProperty); // Invalid
console.log(item.publicProperty); // Valid
Note JavaScript doesn't have the concept of access modifiers as we know them (yet!), so it's only enforced in TypeScript land. Once it hits JavaScript land it's public all the way.
β‘ Static
With static we can add properties to a class and access it without the need to create an instance of the class.
class MyClass {
static value = 13.31;
value = 89.98;
process(num: number) {
return num * MyClass.value;
}
}
console.log(MyClass.value) // 13.31
// const myClassInstance = new MyClass();
// console.log(myClassInstance.value); // 89.98 (using the instance value and not the static value)
π Type Guards (User-defined)
Have you ever written a function that accepts a union type and then experienced trouble when trying to handle the different types, look no further! Type Guards allow us to define a function that will perform a runtime check that will assure you of a single type within some scope.
Some of you may think that typeof
is the solution, but sadly this only works for primitive types.
type MyTypeA = {
typeAProp: number;
otherAProp: string;
sameProp: boolean;
};
type MyTypeB = {
typeBProp: number;
otherBProp: string;
sameProp: boolean;
};
function myFunc(item: MyTypeA | MyTypeB) {
if (isMyTypeA(item)) {
console.log(item.typeAProp, item.otherAProp, item.sameProp) // valid
}
// item.typeAProp // invalid
// item.sameProp // valid
...
}
function isMyTypeA(item: MyTypeA | MyTypeB): item is MyTypeA {
// Return a condition, that guarantees your type is what you are after
return (item as MyTypeA).typeAProp !== undefined;
}
π Partial
Partial will set all properties (except nested properties, we'll touch on this in a bit) as optional.
type MyType = {
RequiredProp1: string;
RequiredProp2: number;
OptionalProp1?: boolean;
}
type PartialMyType = Partial<MyType>;
// This will produce an error, as RequiredProp1 is missing
const item: MyType = {
RequiredProp2: 42
}
// This is valid, as partial marked everything as optional
const partialItem: PartialMyType = {
RequiredProp2: 42
}
As you can see from the example above, Partial
saves us from having to define a nearly duplicate type and marking everything as optional ourselves.
Note there is a built in utility method that does the opposite of Partial
called Required
. Its usage is identical to the above.
Bonus To apply partial to your nested types recursively, use the following snippet
type RecursivePartial<T> = { [P in keyof T]?: RecursivePartial<T[P]> };
// Usage
type EverythingPartial = RecursivePartial<MyType>;
β Pick & Omit
Pick & Omit are useful when it comes to creating a sub type from an external (or internal) interface or types.
// external.ts
interface ExternalInterface {
name: string;
address: string;
age: number;
}
// mycode.ts
// Pick
type MyPickType = Pick<ExternalInterface, 'name' | 'age'>;
// Omit
type MyOmitType = Omit<ExternalInterface, 'address'>;
Both MyPickType
and MyOmitType
end up consisting of the same properties. As the term Pick
suggests, you pick which properties you want on your new type. With Omit
you exclude the properties you list.
Footnote
If I left out a hidden gem or if you need clarification on anything, let me know!
Proof read & edited by my beautiful wife β€!
Remember to #KeepHavingFun
Top comments (0)