Created
May 19, 2018 00:08
-
-
Save chriseppstein/77619f373a7bd4b451fa70ffc980d269 to your computer and use it in GitHub Desktop.
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
declare const EmailTag: unique symbol; | |
type Email = string & typeof EmailTag; | |
function isEmail(email: string): email is Email { | |
return /@/.test(email); | |
} | |
function createEmail(email: string): Email; | |
function createEmail(username: string, domain?: string): Email { | |
if (domain) { | |
return <Email>`${username}@${domain}`; | |
} | |
if (isEmail(username)) { | |
return username; | |
} else { | |
throw new Error(`Not a valid email address: ${username}`); | |
} | |
} | |
namespace Backend { | |
export type Recipients = string[]; | |
} | |
const backend = { | |
async performRequest(url): Promise<any> { | |
return ["[email protected]"]; | |
}, | |
async getRecipients(): Promise<Email[]> { | |
let recipients: Backend.Recipients = await this.performRequest("recipients.json"); | |
return recipients.map((address => createEmail(address))); | |
}, | |
} | |
// Without Tag types `to`` and `from`` are just strings. | |
// So if you want to refactor this function so subject comes last | |
// and becomes optional, you get no help from the type checker. | |
function sendEmail(subject: string, to: Email, from: Email): void { | |
} | |
const OUR_ADDRESS = <Email>"[email protected]"; | |
async function sendEmails() { | |
let recipients = await backend.getRecipients(); | |
for (let recipient of recipients) { | |
sendEmail("Isn't TypeScript Great?", OUR_ADDRESS, recipient); | |
// If you get the order wrong you get a compiler error! | |
// Argument of type '"Isn't TypeScript Great?"' is not assignable to parameter of type 'Email'. | |
// Type '"Isn't TypeScript Great?"' is not assignable to type 'unique symbol'. | |
sendEmail(OUR_ADDRESS, recipient, "Isn't TypeScript Great?"); | |
} | |
} | |
interface EmailLookup { | |
// can't be a tagged string, is that ok? | |
// [email: Email]: Email; | |
[email: string]: Email; | |
} | |
let emails: EmailLookup = { | |
[OUR_ADDRESS]: OUR_ADDRESS, | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment