Dylan Vann

Four Things to Avoid in JavaScript

Common code issues when writing JavaScript.

Things you should never have in your JavaScript code:

  1. Statements starting with [.
  2. Statements starting with (.
  3. Newlines directly after returns.
  4. Semicolons - ;.

For more info see Semicolons in JavaScript, what are they good for?.

Semicolons in JavaScript, what are they good for?

Everything you need to know.

Typing More

const semicolon = 'clearly terminated';
const noSemicolon = 'possibly unfinished'

Some people enjoy typing out an extra character on every line.

It goes without saying you’ll also get to read slightly more.

Harder to Read Diffs

This attribute of semicolons will help you keep code reviewers on their toes.

Harder to Read Diffs When Removing a Chained Method

SemicolonsNo Semicolons
  const thing = another
-   .map(v => v * 2)
-   .filter(v => v / 5);
+   .map(v => v * 2);
  const thing = another
    .map(v => v * 2)
-   .filter(v => v / 5)

This change now shows as affecting two lines, when it really only affects one. I bet our reviewer didn’t see that one coming when they spent time scanning both lines for changes ;).

Harder to Read Diffs When Adding a Chained Method

SemicolonsNo Semicolons
  const thing = another
-   .map(v => v * 2);
+   .map(v => v * 2)
+   .filter(v => v / 5);
  const thing = another
    .map(v => v * 2)
+   .filter(v => v / 5)

This change now shows as affecting two lines, when it really only affects one.

Making It More Difficult to Move Around Lines

SemicolonsNo Semicolons

Shuffling lines is easy, especially if you use vim. If you’d like to swap the last and second last chained methods you need to manually fix the semicolon. This ensures you don’t accidentally modify your code.

Preventing Bugs in Cases That Will Never Come up If the Code You’re Writing Isn’t Terrible

// Something a civilized person might do, creating a variable.
const myNumbers = [1, 2, 3]
[1, 2, 3].forEach() // I didn't make a variable for these.
// I don't even know what they are ¯\_(ツ)_/¯.
// I also don't use prettier, which would pull this line up making my mistake very obvious.

OH NO, A BUG CAUSED BY LACK OF SEMICOLONS! Surely it will take us hours to figure out what’s wrong.

Do you write code like this? If you do you’ll love semicolons.

Conclusion

If you like making it needlessly more difficult to type out, modify, and code review, your code, then you should use semicolons in JavaScript.

For more info see Four Things to Avoid in JavaScript.

How to Incrementally Migrate 100k Lines of Code to Typescript

Migrating a large project to TypeScript even with the loosest settings may be insurmountable. The number of errors is overwhelming.

You may think the best options for fixing this situation is to use a mix of TypeScript and JS (using the allowJs flag), however there is a risk of a large amount of code never being typed because there is not enough incentive and feedback to do so.

If you run TypeScript on a large project after renaming files you may be faced with something like:

Too many TypeScript errors.

Or there could be a lot more errors, this project started with 15k errors.

Unfortunately for a project of any sufficient size, you’re going to run into trouble trying to migrate to TypeScript in one go.

So what are your options?

Dimensions of ComparisonSolo HackathonTeam HackathonEnable on Changed FilesChecklist + Coach TeamSnapshot Test
Fast
High Quality ResultsYMMV
Low Team-Coordination
Non-Breaking For Wip
Reliable On Larger Repos/Messy Code
Can Enable Strict Rules On Day 1
Easy To Add Stricter Rules
Will Achieve 0 Errors
Easily Repeatable For New Rules

Think about it.

Ideally you would like to achieve 0 errors and have an easily repeatable process for preventing new errors. To do this your best option may be creating a snapshot test.

On a high-level, using a snapshot test requires creating a test that runs TypeScript and saves a snapshot of all the errors along with filenames and line numbers. This test will fail anytime lines are shifted on a file with errors, or when new errors are added to the codebase — this serves as a reminder to fix type errors when adding or modifying code. This requires low coordination because it’s an automated approach.

It also becomes very easy to incrementally increase the strictness of type checking, the incremental approach is the same.

In essence, the snapshot test is closer to the code than any checklist process and it requires low team-coordination.

How to create a snapshot test of TypeScript errors?

This repo (DylanVann/typescript-migration-demo) shows a basic example of how to snapshot test TypeScript errors.

Here’s how it works, consider the following 3 untyped JS files:

// add.js
export default function add(a, b) {
  a + b
}
// subtract.js
export default function subtract(a, b) {
  a - b
}
// example.js
import add from './add'
import subtract from './subtract'

add('1', 3, 'hello world')

subtract('1', 3, 'hello world')

When we convert to TypeScript (changing file extensions and adding a tsconfig.json file) this will produce a number of type errors:

Errors after changing file extensions to .ts.

At this point you should run the snapshot test and commit the result. The snapshot of the errors will look something like this:

Snapshot of TypeScript errors.

What happens when I fix or add type errors?

When you fix type errors you can run yarn check-ts -u to update the snapshot, and you will commit something like this:

Diff after fixing TypeScript errors.

If you were to add a type error by accident you would see something like this:

Diff after adding TypeScript errors.

So at this point if you are doing PR reviews your reviewer would probably reject this change.

Using ESLint (or other tools)

This technique applies to any pattern that can be detected using code quality tools. For example it’s possible to write ESLint rules for bad practices specific to your codebase. You can then incrementally remove them using this technique.

Conclusion

Out of all the possible techniques to migrate to TypeScript this one has a lot of things going for it.

How does React Hooks affect testing?

How does React Hooks change traditional approaches to React app architecture and testing?

Not very much:

  • You should still write most of your components as stateless functional components (not using hooks).
  • You should still use a state management library for 90% of your application state.

Hooks should be reserved for special cases:

  • Animations.
  • Integrating non-react libraries.
  • Creating more complex reusable components (should be done sparingly).

Anytime you’d currently use a class component, you could instead use hooks. Also, if you haven’t already been avoiding class components you should avoid them.

Historically avoiding class components has been a good practice in React, and I think avoiding using Hooks for most components will continue to be a good approach.

Benefits of hooks over class components:

Most business logic should still live in your state management library, and it can be tested in isolation there instead of being tested in React components.

Reusable/stateful/complex components that require hooks should be tested using more integration like tests. The best library available for doing this right now is react-testing-library. The philosophy of react-testing-library is that your tests should resemble how your code is used, and it should test what your users care about. This works very well for testing hooks, because using this approach wether or not a component uses them is an implementation detail that should not affect how a test is written.

At some point there are going to be more state management libraries providing hooks APIs. For these I believe it would still be best to call them in container components, which could now be written as function components. These containers should be relatively simple, and could probably be untested, similar to most Redux containers.

In summary, if you want an app to be as maintainable as possible I think you should treat most hooks the way you treat class components now, avoiding using them in favor of relying on a state management library 90% of the time.

Ant Design Draggable Modal

The Modal from Ant Design, draggable.

GitHub

Trying something out with React Hooks.
1 of 5
© 2020 Dylan Vann