-
-
Notifications
You must be signed in to change notification settings - Fork 44
Code Style Guide
Please follow the AirBnb Style Guide. There are, however, some exceptions. If you find any code does not follow the guidelines linked and specified below, please either create a new issue or fork and create a new pull request.
else if
or else
must start on a new line.
// bad
if (condition) {
expression;
} else {
expression;
}
// bad
if (condition)
{
expression;
}
else
{
expression;
}
// good
if (condition) {
expression;
}
else {
expression;
}
?
and :
must start on a new line if the expression is too long to fit one line.
// bad
condition ?
expression :
expression
// good
condition
? expression
: expression
// also good
condition
? expression
: expression
// best (but requires the whole construct to fit one line)
condition ? expression : expression
// bad
condition &&
condition ||
condition
// good (because && has a higher precedence, but it must fit one line then)
condition && condition
|| condition
// also good
condition
&& condition
|| condition
// also good (useful if conditions are so long that parenthesis would improve readability)
(
condition
&& condition
)
|| condition
// also good (useful if conditions are so long that parenthesis would improve readability)
(
condition
&& condition
)
|| condition
// good (but requires the whole construct to fit one line)
condition && condition || condition
// good (but requires the whole construct to fit one line)
condition && (condition || condition) && condition
// good
condition
&& (
condition
|| condition
)
&& condition
// also good
condition
&& (condition
|| condition)
&& condition
// also good
condition
&& (condition || condition)
&& condition
// bad
condition
&& (condition
|| condition)
&& condition
// bad
condition
&& (condition
|| condition)
&& condition
In Functional Programming, we don't have statements so we also don't need semicolons. JavaScript is able to insert semicolons on it's own (in almost all cases) so we don't need visual clutter.
Functions (and methods) have to be fully curried. There should not be partial function application, as this would cause different possibilities in calling functions. I want to enforce one style:
const add = (a: number) => (b: number) => a + b
// worst
const addedNumbers = add(2)(3)
// still bad
const addedNumbers = add(2) (3)
// still bad
const addedNumbers = add (2)(3)
// good
const addedNumbers = add (2) (3)
// multiline (useful is function name or arguments are long) ...
const addedNumbers = add (2)
(3)
// ... or (useful if the above is too long) ...
const addedNumbers =
add (2)
(3)
// ... with defined generics (add has no generics here, but lets just assume it has)
const addedNumbers =
add <number, number>
(2)
(3)
// ... or (useful if the function name is too long)
const addedNumbers =
add
(2)
(3)
This style is readable while having curried functions. It's derived from the Haskell style of calling functions, where the arguments are separate by one whitespace as well:
add :: Int -> Int -> Int
add 2 3
Fun fact: add (2) (3)
is valid Haskell, it just contains unnecessary groupings.
// good
const x = myFunction (otherFunc ("Hi")) (3)
// good (such line breaks (compare to above) are usually needed either because of readability
// or because the line would be too long otherwise)
const x = myFunction (otherFunc ("Hi"))
(3)
// also good
const x = myFunction (otherFunc ("Hi")
("Other string"))
(3)
// also good
const x = myFunction (otherFunc ("Hi") ("Other string"))
(3)
// bad
const x = myFunction (otherFunc ("Hi")
("Other string")) (3)
// very bad ("Other string" seems to be a param of myFunction but its not)
const x = myFunction (otherFunc ("Hi")
("Other string")) (3)
// very bad ("Other string" seems to be a param of myFunction but its not, but 3 is)
const x = myFunction (otherFunc ("Hi")
("Other string"))
(3)
If you need to use a class (e.g. the custom data structures Maybe, List a.s.o. are implemented as classes, consider the following styistic rules for using methods:
// bad
maybeValue.fmap(R.inc)
// still bad
maybeValue.fmap (R.inc)
// still bad
maybeValue .fmap(R.inc)
// good
maybeValue .fmap (R.inc)
This way, a method seems to be more like an infix function. Instance methods are always curried, too.
// very bad
Maybe.fmap(R.inc)(maybeValue)
// still bad
Maybe.fmap (R.inc) (maybeValue)
// still bad
Maybe .fmap (R.inc) (maybeValue)
// good
Maybe.fmap (R.inc) (maybeValue)
Static methods do not need a space before the dot because Maybe
is no value. So Maybe.fmap
as a whole is the function (name).
This way, you can also better differenciate between static and instance methods.
Do not use named function expressions if using function
, e.g. const fn = function longFunctionName () { ... }
. Prefer arrow functions, which must be declared using const fn = () => { ... }
, though.
Concerning Arrow Functions 8.4: Only use parentheses when there is more than one argument, do not use even if the function uses braces (actually you don't need parentheses at all, because all functions should be curried).
Concerning Modules 10.2: Use wildcards when there are too many imports or for the sake of consistency across files (especially used for files in src/types
, e.g. * as Wiki
).
Concerning Modules 10.3: Prefer shorter syntax.
Concerning Modules 10.6: Do not use default exports, as possible renaming cannot benefit from TypeScript's ability to find all symbol references.
Concerning Arrow Functions 10.8: Put everything on one line, as it is more compact. TypeScript warns when there are missing or unnecessary imports anyway.
- Object 3.5: Group object shorthand properties
- Arrow Functions 8.3: Wrap expression in parentheses
- Arrow Functions 8.5: Avoid confusing arrow function syntax with comparison operators
- Arrow Functions 8.6: Enforce the location of arrow function bodies with implicit returns
-
Variables 13.3: Group
const
s andlet
s - Comparison 15.8: Enclose mixing operators in parentheses
A lot of areas are already covered by TSLint and it's plugins. Please use TSLint, it makes following the guidelines a lot easier!
Main Tables
- Advantages, Disadvantages, Special Abilties
- Attributes
- Blessings
- Books
- Cantrips
- Combat Techniques
- Cultures
- Equipment
- Experience Levels
- Liturgical Chants
- Profession Variants
- Professions
- Race Variants
- Races
- Skills
- Spells
- UI
Subtables
Additional Tables
Programming
Data Structures