Types — Testing

We have our function, but now we need to cover it again with tests.

Let’s revisit them.

Passing any property other than value or checked will throw an Exception.

Wait, we actually don’t have this problem anymore because we defined Bind; the type system will enforce that this rule is respected.

Ok, moving on to the next:

Passing something other than input or other valid HTML Element tags will throw an Exception

Um, we don’t cover this one, but I think types can help here:

type Tag = 'input'|'select'|'textarea'

function h$b(tag: Tag, bind: Bind): Component

Nice! If we try to use anything else than input , select or textarea the Typescript compiler will yell at us, forcing us to use a valid tag.

Next one:

Only input tag is allowed for checked property

Let’s think a little bit more here: we can use value for all Tags we just defined, but checked only with input . Interestingly enough, Typescript can help here too, thanks to function overloading:

type Tag = 'input'|'select'|'textarea'

type BindValue = { value: StreamBox }

type BindChecked = { checked: StreamBox } function h$b(tag: Tag, bind: BindValue): Component

function h$b(tag: 'input', bind: BindChecked): Component

This definition can look intimidating, but it’s just encoding our acceptance criteria for this function: checked can be bound only to an input element, while value can be used for the defined elements. The code will be shared across the two definitions.

Another test skipped, next one, please!

Setting a value to a StreamBox bound to value will stringify it

Setting a value to a StreamBox bound to checked will make it a boolean

Said in other terms: value only works with strings and checked only with booleans.

We can definitely solve this by enhancing the StreamBox definition:

type BindValue = { value: StreamBox<string> }

type BindChecked = { checked: StreamBox<boolean> }

If you are not familiar with generics, this is just informing the compiler that StreamBox contains a value of type string for value and a boolean for checked .

We can add any other type between <> , that why it’s called generic.

Here are the last two acceptance criteria:

Changing a StreamBox value also changes Eelement value Changing Element value also changes StreamBox value

No shortcuts here, we just need to write tests. This is the actual business logic for this particular function; the rest is just details.

In the end, we covered 5 acceptance criteria out of 7 by using the type system. That’s an incredible result, especially because our function logic and code is now free of all the defensive code and exceptions that we had to put in place in the Javascript version, making it simpler and less prone to error.