Skip to content

Commit

Permalink
Nominal types
Browse files Browse the repository at this point in the history
  • Loading branch information
orta committed Aug 18, 2019
1 parent d9a2c3e commit c0b385f
Showing 1 changed file with 66 additions and 0 deletions.
66 changes: 66 additions & 0 deletions Examples/TypeScript/Meta-Types/Nominal Typing.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
// A nominal type system means that each type is unique
// and even if types have the same data you cannot assign
// across types.

// TypeScript's type system is structural, which means
// if the type is shaped like a duck, it's a duck. If a
// goose has all the same attributes as a duck, then it also
// is a duck.

// This can have drawbacks, for example there are cases
// where a string or number can have special context and you
// don't want to ever make the values transferrable. For
// example:
//
// - User Input Strings (unsafe)
// - Translation Strings
// - User Identification Numbers
// - Access Tokens

// We can we get most of the value from a nominal type
// system with a little bit of extra code.

// We're going to use an intersectional type, with a unique
// constraint in the form of a property called __brand (this
// is convention) which makes it impossible to assign a
// normal string to a ValidatedInputString.

type ValidatedInputString = string & { __brand: "User Input Post Validation" }

// We will will use a function to transform a string to
// a ValidatedInputString - but the point worth noting
// is that we're just _telling_ TypeScript that it's true.

const validateUserInput = (input: string) => {
const simpleValidatedInput = input.replace(/\</g, "≤")
return simpleValidatedInput as ValidatedInputString
}

// Now we can create functions which will only accept
// our new nominal type, and not the general string type.

const printName = (name: ValidatedInputString) => {
console.log(name)
}

// For example, here's some unsafe input from a user, going
// through the validator and then being able print:

const input = "\n<script>alert('bobby tables')</script>"
const validatedInput = validateUserInput(input)
printName(validatedInput)

// On the other-hand passing the un-validated string to
// printName will raise a compiler error:

printName(input)

// You can read a comprehensive overview of the
// different ways to create nominal types, and their
// trade-offs in this 400 comment long GitHub issue
//
// https://github.com/Microsoft/TypeScript/issues/202
//
// and this post is a great summary
// https://michalzalecki.com/nominal-typing-in-typescript/
//

0 comments on commit c0b385f

Please sign in to comment.