Skip to content

Instantly share code, notes, and snippets.

@adamrenklint
Created September 16, 2016 13:22
Show Gist options
  • Save adamrenklint/510e9590913fe4a2a4c40e4b67988735 to your computer and use it in GitHub Desktop.
Save adamrenklint/510e9590913fe4a2a4c40e4b67988735 to your computer and use it in GitHub Desktop.
Immutable data structures in TypeScript
import { freeze, assoc } from 'icepick'
interface User {
/**
* Name of the user
*/
readonly name: string
/**
* Age of the user
*/
readonly age: number
}
const createUser = (values: User): User => freeze(values)
// safe constructor, check
const adam = createUser({ name: 'Adam', age: 33 })
// safe from mutations, check
adam.name = 'asdas'
// safe from adding fields, check
adam.foo = 'asdas'
// safe reads with autocomplete, check
adam.age
// but not working, safe writes :(
const adam2 = assoc(adam, 'name', 123) // wrong type
const adam3 = assoc(adam, 'nmae', 'Adam2') // wrong key
type UserCollection = User[]
// interface ImmutableArray {
// push(input:void): void
// }
const createUserCollection = (users: User[]): UserCollection => freeze(users)
const users = createUserCollection([adam, adam2])
@adamrenklint
Copy link
Author

// Use typed-immutable types to type check function parameters

const check = (name, value, type) => {
  if (__PROD__) return
}

import { Maybe, Union } from 'typed-immutable'
import { check, PositiveNumber } from 'lib/type'
import { Cursor } from './models'

function moveCursorLeft(cursor, steps, message, context) {
  check('cursor', cursor, Cursor)
  check('steps', steps, PositiveNumber)
  check('message', message, Maybe(String)) // check that message is either string or nully, not other type
  check('context', context, Maybe(Union(String, Number))) // if context is defined, it must be either String or Number

  // do the stuff
}

/**
 * Function of some kind
 */
const testFunctionParamType = (name, resolver, options) => {

}

// USING THE TEST HELPER
// import { testArgumentType } from 'lib/type'
testFunctionParamType(
  'moveCursorLeft:steps',
  arg => moveCursorLeft(cursor, arg, 'asd', 'asd'),
  {
    valid: [0, 100, 9999999],
    invalid: [null, false, -1, -99999, 'null', true]
  }
)



// how to test an object of a certain shape, without it having to be an instance of a type?
function doThing(options = {}) {
  // check('options', options, Object)
  // check('options.size', options.size, PositiveNumber)
  // check('options.comment', options.comment, String)
  //or
  check('options', options, {
    size: PositiveNumber(0), //default to 0, implicityly Maybe
    comment: String('default comment'), // default string value
    others: Array()
  })
}
// could I also deeply add/define default object members?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment