JavaScript naming scheme: TypexJS
Tags: javascript
Published: 2019-11-20 06:42:17

One of the most useful principle of software development which should be permanently kept in mind is not a new one. Actually, it's an almost millenial assertion: **<q>Entities must not be multiplied without necessity</q>**, a sentence frequently associated with the [Occam's razor] concept. Despite his canonical age, the validity of the sentence remains intact in the sofware engineering field and it has been adaptated in many ways (the [KISS] principle is one among many [others]).


Therefore, what are the implications of such a _law_ for a JavaScript programmer? And why is a computer language typing concept related to it?


## A dispute about names and types


Every developer knows that JavaScript is not a static typed language, a useful feature eliminating lots of bugs (a language like Typescript has been created as a remedy to that important lack of safety). Even for code modules counting less than a few tens of lines, it's easy to forget what exactly is the type of a variable declared at the begining of the file and then make a mistake when assining a wrong type to that variable.

**[TypexJS]** is a simple convention designed to avoid such mistakes: by only adding a mnemonic letter at the end of each variable identifier to specify its type (of course, this scheme also applies to constants).

This simple adjonction has two main benefices:
+ it gathers tightly related variables in a consistent semantic field;
+ it simplifies identifier derivations.

Just an example, taken from [MDN String documentation]. The JavaScript `String.prototype.split` method returns an array of Strings:
```
var str = 'The quick brown fox jumps over the lazy dog.';
var words = str.split(' ');
```

Two different words for two tightly related entities! Isn't it semantically more meaningful to use the same identifier with different specifiers?
```
const sentence_s = 'The quick brown fox jumps over the lazy dog.';
const sentence_a = sentence_s.split(' ');
```

A more tricky example (with a smart inline type coercion tricks!):
```
let number_s = '123'
let number_n = +number_s    //: cast to Number
number_s = '' + ++number_n  //: cast to String
```

## Types specifiers


**TypexJS** naming scheme applies to all primitive immutable types:
+ Null
+ Undefined
+ Boolean
+ Number
+ BigInt
+ String
+ Array
+ Object
+ Symbol


It extends to specific Object types:
+ Class
+ RegExp
+ Function


The suffix specifying the type is a single letter preceded by an underscore character:
+ **lowercase letters**
for "wrapped" types: _Boolean_, _Number_, _BigInt_, _String_, _Array_, _Object_, _Symbol_, _Function_, _Class_, _RegExp_ 
(see [ MDN Primitive description])
+ **uppercase letters** for "unwrapped" types: _Null_, _Undefined_.


| Type       | Suffix |
| -----------|:------:|
| Null       | __N_   |
| Undefined  | __U_   |
| Boolean    | __b_   |
| Number     | __n_   |
| BigInt     | __i_   |
| String     | __s_   |
| Array      | __a_   |
| Object     | __o_   |
| Symbol     | __y_   |
| Class      | __c_   |
| RegExp     | __r_   |


To convey even more meaningful information, function identifiers follow a slightly different scheme: **two underscore** characters before the type specifier **of the returned value**. Consequently, if a function doesn't return anything (`void` function), the _v_ letter is used for its suffix!

| Function return is | Suffix |
| -------------------|:------:|
| Null               | ___N_  |
| Undefined          | ___U_  |
| Boolean            | ___b_  |
| Number             | ___n_  |
| BigInt             | ___i_  |
| String             | ___s_  |
| Array              | ___a_  |
| Object             | ___o_  |
| Symbol             | ___y_  |
| Class              | ___c_  |
| RegExp             | ___r_  |
| Function           | ___f_  |
| Void               | ___v_  |


```
const awesome__s = () => 'An awesome String'
const clone__s = awesome__s
```

In case of a function returning different types of value, we just omit the type character:

```
const silly__ = string_b => string_b ? 'A weird String' : 1234
```

We could do the same for a variable accepting different kinds of type, but is it really a good practice?
```
let hybrid_ = 'A String'
hybrid_ = 1234  //: What a mess!
```

## Full example


```
const DOM_siblings__a = selector_s =>
{
  const node_e = document.querySelector( selector_s )
  return !node_e ?
    null :
    Array.prototype.filter
      .call( node_e.parentNode.children, sibling_e => sibling_e !== node_e )
}

const DOM_listReverse = selector_s =>
{
  const node_a = Array.prototype.slice.call( document.querySelectorAll( `${selector_s} li` ))
  node_a.forEach( node_e => node_e.parentNode.insertBefore( node_e, node_e.parentNode.firstChild ) )
}
```

The previous code shows an **exception** to the specifiers convention used by **TypexJS**: for `DOM` elements, it seems more appropriate to use the `_e` suffix (for _element_, because the `_N` suffix is already used for a `Null` value) than the `_o` suffix used for `Object`.


The example code shows another singularity: we can instantly differenciate JavaScript and browser specific functions or methods from our own code functions and methods. Our identifiers have a letter suffix where JS and browser identifiers have nothing. Therefore, we can safely use exactly the same names:
```
const myWindow = window  // usual way
const window_o = window  // smarter isn't it?
```

Hence, everytime we want to override some JavaScript or DOM function
(or any browser specific, third-party library function, etc.), we can safely do it while keeping a semantic coherency with the original function.


This very simple and easy to memorize convention can help you to write a better code while conveying more information about it as well as shortening its documentation. You can find more details about **[TypexJS]** visiting its dedicated site and put comments or questions if you see fit.

[comment]: # (======== Links ========)

[TypexJS]: https://typexjs.netlify.com
[Occam's razor]: http://www.irishphilosophy.com/2014/05/27/who-sharpened-occams-razor/
[KISS]: https://en.wikipedia.org/wiki/KISS_principle
[others]: https://effectivesoftwaredesign.com/2013/08/05/simplicity-in-software-design-kiss-yagni-and-occams-razor/
[MDN String documentation]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/split
[ MDN Primitive description]: https://developer.mozilla.org/en-US/docs/Glossary/Primitive