Why I Prefer 'function' Declarations for Top-Level Symbols (But Won't Use Them Anymore)

manuartero

Manuel Artero Anguita 🟨

Posted on October 23, 2024

Why I Prefer 'function' Declarations for Top-Level Symbols (But Won't Use Them Anymore)

Today, we’ve decided to use arrow functions exclusively at work.

We have a common ESLint config, and the team voted to unify this rule across all projects.

And honestly I'm not a fan of this particular rule

Personally... function declarations feels more expressive, at least for top-level symbols:

some-screen-of-my-app.tsx

import {} ...

export function SomeScreen(props: Props) {
  const { myContext } = useMyContext()
  const [state, setState] = useState()

  const doSomething = () => { ... }
  const handleSomething = () => { ... }

  return <>...</>
 }

function SomeInternalComponent() { ... }
Enter fullscreen mode Exit fullscreen mode

This is how i'm used to write components: declaring a function feels like a chapter title in a novel.

function Chapter3(storySoFar: Props) {
   // where the Hero meets the Villain
}
Enter fullscreen mode Exit fullscreen mode

But I do understand the team need: depending on the original author of a module we might find at first level const () => {} or function.

The main argument is that "arrow functions are more readable" (which i disagree with)

import {} ...

const SomeInternalComponent = () => { ... }

export const SomeScreen = (props: Props) => {
  const { myContext } = useMyContext()
  const [state, setState] = useState()

  const doSomething = () => { ... }
  const handleSomething = () => { ... }

  return <>...</>
 }
Enter fullscreen mode Exit fullscreen mode

I tried to find some technical advantage to support my preference... some nerd *pitimini* [ something small or insignificant ] that moves the balance on my benefit but since we all agree on the following:

  • No Classes (just functions)
  • No global stuff (modern modules)
  • No this

There are no significant differences between each one.

Diving into Details:

const foo = () => { ... }

  • No hoisting
  • function's name is derived from the variable's name ("foo")
  • Can't be overwritten later like foo=...
  • Doesn't create the prototype object foo.prototype
  • Can't be used as a constructor new foo()
  • Doesn't have arguments
  • this value is defined by where the function is declared

function foo() { ... }

  • Hoisting
  • function name is obv.
  • Can be overwritten like foo = ...
  • Creates the object prototype foo.prototype
  • new is allowed like: new foo() (which would link the prototype)
  • this value is defined by how the function is called

In the end, I prefer the Superior Clarity of function for top-level components, but the will of the many prevails.
Kidding, I will adapt. Having a unified style will help to maintain a cohesive codebase.

😭😭😭.


thanks for reading

💖 💪 🙅 🚩
manuartero
Manuel Artero Anguita 🟨

Posted on October 23, 2024

Join Our Newsletter. No Spam, Only the good stuff.

Sign up to receive the latest update from our blog.

Related