Перейти к содержанию

Руководство по стилю и соглашения по кодированию

Люди спрашивали меня, что я думаю по этому поводу. Лично я не навязываю их своим командам и проектам, но эти соглашения отлично выступают мировым судьёй и полезны для поддержания консистентности кодовой базы. Есть и другие более важные вещи и они описаны в главе с советами (например, утверждение типа это плохо, сеттеры свойств это плохо) 🌹.

Переменная и функция

  • Используйте camelCase для имен переменных и функций

Причина: соглашение в JavaScript

Плохо

var FooVar;
function BarFunc() {}

Хорошо

var fooVar;
function barFunc() {}

Класс

  • Используйте PascalCase для имен классов.

Причина: на самом деле это довольно привычно для стандартного JavaScript.

Плохо

class foo {}

Хорошо

class Foo {}
  • Используйте camelCase для членов класса и методов

Причина: логично следует из соглашения об именах переменных и функций.

Плохо

class Foo {
    Bar: number;
    Baz() {}
}

Хорошо

class Foo {
    bar: number;
    baz() {}
}

Интерфейс

  • Используйте PascalCase для именования.

Причина: аналогично классу

  • Используйте camelCase для элементов.

Причина: аналогично классу

  • Не используйте префикс I

Причина: нет такого общего соглашения. lib.d.ts определяет важные интерфейсы без символа I (например Window, Document и т. д.).

Плохо

interface IFoo {}

Хорошо

interface Foo {}

Тип

  • Используйте PascalCase для именования.

Причина: аналогично классу

  • Используйте camelCase для элементов.

Причина: аналогично классу

Пространства имен

  • Используйте PascalCase для именования.

Причина: cоглашение, которого придерживается команда TypeScript. Пространства имен фактически представляют собой просто класс со статическими членами. Имена классов: PascalCase => имена пространств имен: PascalCase

Плохо

namespace foo {}

Хорошо

namespace Foo {}

Перечисление

  • Используйте PascalCase для именования.

Причина: аналогично классу

Плохо

enum color {}

Хорошо

enum Color {}
  • Используйте PascalCase для именования элементов перечисления.

Причина: соглашение, которому следует команда TypeScript, то есть создатели языка, например SyntaxKind.StringLiteral. Это также помогает с переводом (генерацией кода) других языков в TypeScript.

Плохо

enum Color {
    red,
}

Хорошо

enum Color {
    Red,
}

Null vs. Undefined

  • Предпочитаю не использовать ни то, ни другое из-за явной недоступности

Причина: эти значения обычно используются для сохранения согласованности между значениями. В TypeScript вы используете типы для указания структуры

Плохо

let foo = { x: 123, y: undefined };

Хорошо

let foo: { x: number; y?: number } = { x: 123 };
  • Используйте undefined в общем случае (но рассмотрите возможность возврата такого объекта, как {valid:boolean, value?:Foo} вместо этого)

Плохо

return null;

Хорошо

return undefined;
  • Используйте null, если он является частью API или является традиционным

Причина: это обычное дело в Node.js, например error имеет значение null для колбэков.

Плохо

cb(undefined);

Хорошо

cb(null);
  • Используйте проверку на истинность объектов, являющихся null или undefined

Плохо

if (error === null)

Хорошо

if (error)
  • Используйте == null / != null (а не === / !==) для проверки наличия null / undefined в примитивах, но не для других ложных значений (например '', 0, false), например:

Плохо

if (error !== null) // не исключает undefined

Хорошо

if (error != null) // исключает и null и undefined

Форматирование

Компилятор TypeScript поставляется с очень хорошим сервисом форматирования. Какой бы результат он ни давал по умолчанию, он достаточно хорош, чтобы уменьшить когнитивную нагрузку в команде.

Используйте tsfmt для автоматического форматирования кода в командной строке. Кроме того, ваша IDE (atom/vscode/vs/sublime) уже имеет встроенную поддержку форматирования.

Примеры:

// Пробел перед типом, т.е. foo:<пробел>string
const foo: string = 'hello';

Кавычки

  • Предпочитаю одинарные кавычки ('), если не экранирую.

Причина: так делают другие команды JavaScript (например airbnb, standard, npm, node, google/angular, facebook/react). Печатать легче (на большинстве клавиатур shift не требуется). Команда Prettier также рекомендует одинарные кавычки

Двойные кавычки не лишены достоинств: они упрощают копирование и вставку объектов в JSON. Позволяет людям использовать другие языки для работы без изменения символа кавычек. Позволяет использовать апострофы, например He's not going. Но я бы не стал отклоняться от того, что справедливо решило сообщество JS.

  • Если вы не можете использовать двойные кавычки, попробуйте использовать обратные галочки (`).

Причина: обычно они предоставляют возможность удобно работать со сложными строками.

Пробелы

  • Используйте 2 пробела. Не табы.

Причина: так делают другие команды JavaScript (например airbnb, idiomatic, standard, npm, node, google/angular, facebook/react). Команды TypeScript/VSCode используют 4 пробела, но определенно являются исключениями в экосистеме.

Точка с запятой

  • Используйте точку с запятой.

Причины: явная точка с запятой помогает инструментам форматирования языка давать стабильные результаты. Отсутствие ASI (автоматическая вставка точки с запятой) может сбить с толку новых разработчиков, например. foo() \n (function(){}) будет одним оператором (а не двумя). TC39 предупреждает об этом. Примеры команд использующих точку с запятой: airbnb, idiomatic, google/angular, facebook/react, Microsoft/TypeScript.

Массив

  • Описывайте массивы как foos: Foo[] вместо foos: Array<Foo>.

Причины: легче читать. Это соглашение использует команда TypeScript. Легче узнать, что что-то представляет собой массив, так как мозг обучен обнаруживать [].

Имя файла

Именуйте файлы в camelCase. Например accordion.tsx, myControl.tsx, utils.ts, map.ts и т.д.

Причина: стандарт для многих JS-команд.

тип vs. интерфейс

  • Используйте тип, когда вам может понадобиться объединение или пересечение:
type Foo = number | { someProperty: number }
  • Используйте интерфейс, если вы хотите использовать extends или implements, например:
interface Foo {
  foo: string;
}
interface FooBar extends Foo {
  bar: string;
}
class X implements FooBar {
  foo: string;
  bar: string;
}
  • В иных случаях используйте то, что вам больше нравится.