Last active
March 31, 2021 07:14
-
-
Save daniel-shuy/c648257cf151e14eae5ea8426b19a27e to your computer and use it in GitHub Desktop.
Examples of TypeScript's powerful type system
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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! |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// 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 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// 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