TypeError: ‘Win’ and ‘NotTyped’ have no overlap
Tags: webdev, javascript, typescript, testing
Published: 2023-11-19 22:11:20

Tests save you a lot of pain and make even a complicated refactor seem *easy*.

Wait… isn’t this about typing?

## Typing is also testing!

There’s a reason why types are considered `static testing`.

Recently I had to both refactor and add more things in one function.

Before it would get data from the ORM, which would give a complex object that it would further be transformed, until returning data in one format.

After the changes, it would get data from more than one place, not to mention a few other steps it didn’t have before to further manipulate the data, and finally the catch: it should still return the data in the same format.

## The example

I’m not good with examples, but here’s a try.

It’s still a lot simpler than what I had to do but should work as an example.

### The untyped problem

```js
function func(args) {
	return {
		a: args.a + (args.c.d
			? args.c.f.g.reduce((a, b) => a + b)
			: 0
		),
		b: args.c.d ? args.c.e : args.b,
		c: args.h.i
			? args.h.j.reduce((a, b) => a + b)
			: args.h.j.reduce((a, b) => a * b)
	};
}
```

Without types, there's just a bunch of random things.

And now I’m saying you need a couple of sources while maintaining the same output.

After crying for a while, you open the debugger and `console.log` every single line like there’s no tomorrow. Run, step debugger, check the log… again and again, and hope you manage to still have the same output.

### With types…

I’m using Typescript here, but I actually used JSDoc on the project (you can probably find other times I’ve talked about it).

```tsx
type TypeIn1 = {
	a: number,
	b: string,
	c: {
		d: boolean,
		e: string,
		f: {
			g: number[],
		},
	},
	h: {
		i: boolean,
		j: number[],
	},
};

type TypeOut = {
	a: number;
	b: string;
	c: number;
};

function func(args: TypeIn1): TypeOut {
	return {
		a: args.a + (args.c.d
			? args.c.f.g.reduce((a, b) => a + b)
			: 0
		),
		b: args.c.d ? args.c.e : args.b,
		c: args.h.i
			? args.h.j.reduce((a, b) => a + b)
			: args.h.j.reduce((a, b) => a * b)
	};
}
```

Let’s say this is what it was.

As an aside, of course, good naming will help a lot. But even then it could give you problems: is the date a string or Date? Is the id a string or number? Am I spelling it right? Does this exist in this object or the other?

All of that is solved with types. And then I want to add new data.

```tsx
type TypeIn2 = {
	r: number,
	s: string,
	t: {
		u: boolean,
		v: number[],
	},
	w: boolean,
};

type TypeIn3 = {
	x: boolean,
	y: string,
	z: number[],
};
```

Again, this is a really simple and naive example, but how many times I had to debug or run the code and/or log it until I got the change I wanted, let’s say to this?

```tsx
function func2(
	args: TypeIn2,
	other: TypeIn3,
): TypeOut {
	return {
		a: args.r + (args.t.u
			? args.t.v.reduce((a, b) => a + b)
			: 0
		),
		b: args.w ? args.s : other.y,
		c: other.x
			? other.z.reduce((a, b) => a + b)
			: other.z.reduce((a, b) => a * b),
	};
}
```

## Zero time debugging, Zero console.log

If you know the exact type of what's going in and out. The rest is just pure coding.

No debugging was needed.

No `console.log` scattered through all the code.

Times running the code? Zero.

I just changed the input types and… coded!

I then saved it, ran it only once and it just worked. Just like that.

## Sometimes things aren’t that complicated

We are the ones that end up complicating things.

It’s really amazing that people still avoid typing when it does so much.

### Some claim it’s hard…

Do you know what's hard? 

Finding a misspelled object, sometimes even typing can be hard and you end up copying paste everywhere and then, of course, paste in the wrong places and then have to find where.

### Some claim it’s verbose…

Do you know what’s verbose? 

Errors and stack traces.

### But I just want to code.

Me too… that’s why I type stuff and stop wasting coding time with debugging for obvious, with types, errors, or logs to find out what’s going in and out of functions I’m writing.

## Outro

It, of course, doesn’t solve all the problems.

But it brings much more than any other problem you might have with it while subtracting a lot more problems that you would have otherwise.

And “type gymnastics” can happen, but unless you’re doing something like a library, that multiple people will use over and over… yes, while some complicated types can be more helpful than generic ones, anything is better than nothing.