Skip to content

Instantly share code, notes, and snippets.

@daniel-shuy
Last active March 31, 2021 07:14
Show Gist options
  • Save daniel-shuy/c648257cf151e14eae5ea8426b19a27e to your computer and use it in GitHub Desktop.
Save daniel-shuy/c648257cf151e14eae5ea8426b19a27e to your computer and use it in GitHub Desktop.
Examples of TypeScript's powerful type system
enum Weekday {
MONDAY = 'MONDAY',
TUESDAY = 'TUESDAY',
WEDNESDAY = 'WEDNESDAY',
THURSDAY = 'THURSDAY',
FRIDAY = 'FRIDAY',
}
enum Weekend {
SATURDAY = 'SATURDAY',
SUNDAY = 'SUNDAY',
}
enum Day {
...Weekday,
...Weekend,
}
type Day = Weekday | Weekend;
// Usage Example
// see enum-map.ts below first
type EnumMap<E, V> = {
[K in keyof E]: V
};
const daysToLabels: EnumMap<Day, string> = {
MONDAY: 'Monday',
TUESDAY: 'Tuesday',
WEDNESDAY: 'Wednesday',
THURSDAY: 'Thursday',
FRIDAY: 'Friday',
SATURDAY: 'Saturday',
SUNDAY: 'Sunday',
};
function tgif(day: Day) {
if (input === Weekday.FRIDAY) {
alert('Thank God');
}
alert(`It's ${daysToLabels[day]}!`);
}
tgif(Day.FRIDAY); // Thank God It's Friday!
const sunday: Day = Weekend.SUNDAY;
tgif(sunday); // It's Sunday!
// Note that this only works with String enums.
// If you want to use it with a Numeric enum or Heterogenous enum, convert it to a String enum, then move the values to an EnumMap<E, number> or EnumMap<E, any> respectively.
type EnumMap<E, V> = {
[K in keyof E]: V
};
// Usage Example
enum Direction {
NORTH = 'NORTH',
SOUTH = 'SOUTH',
EAST = 'EAST',
WEST = 'WEST',
}
const directionsToAbbreviations: EnumMap<typeof Direction, string> = {
// unlike using a Map<Direction, string>, this is exhaustive. If any Enum value is not mapped, it will not compile.
NORTH: 'N',
SOUT: 'S',
EAST: 'E',
WEST: 'W',
};
alert(directionsToAbbreviations[Direction.NORTH]); // N
// Allows usage of Rest Parameters in type parameters
export type RestParam<T> = T | T[];
export function restParamToArray<T>(restParam: RestParam<T>): T[] {
return Array.isArray(restParam) ? restParam : [restParam];
}
// Usage Example
enum Role {
USER,
ADMIN,
}
enum Permission {
READ,
WRITE,
}
class Authorizer {
protected rolesToPermissions: Map<Role, Set<Permission>>;
constructor(rolesToPermissions: Map<Role, RestParam<Permission>>) {
this.rolesToPermissions = new Map(
Array.from(rolesToPermissions, ([role, permissions]) =>
[role, new Set(restParamToArray(permissions))]
)
);
}
roleHasPermission(role: Role, permission: Permission): boolean {
const permissions = rolesToPermissions.get(role);
return permissions?.has(permission);
}
}
const authorizer = new Authorizer(new Map<Role, RestParam<Permission>>([
[Role.USER, Permission.READ],
[Role.ADMIN, [
Permission.READ,
Permission.WRITE,
]],
]));
alert(authorizer.roleHasPermission(Role.USER, Permission.WRITE)); // false
alert(authorizer.roleHasPermission(Role.ADMIN, Permission.WRITE)); // true
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment