Наткнувшись на материал по принципам чистый код для TypeScript и прочитав его решил взяться за его перевод. Здесь я хочу поделиться с вами некоторыми выдержками из этого перевода, так как некоторые моменты чистого кода для TypeScript повторяют такие же принципы для JavaScript, я их здесь описывать не буду, если будет интересно перевод для JS уже публиковался на хабре(@BoryaMogila) или же можете ознакомится с ними в первоисточнике.

Для начала давайте же разберемся что такое, эти принципы чистого кода. Но дать четкого определения чистого кода к сожалению вряд ли получится. Отчасти это все зависит от людей, так например приходишь в музей рассматриваешь картину и думаешь что за уродство, но тут же подходит другой человек и говорит, какое великолепие. Да у нас есть какие определенные, общие черты мира, где мы можем сказать, что то или иное красиво, но дать всему этому определение мы точно не сможем. Так и здесь это всего лишь какие то небольшие критерии этой красоты, соблюдение которых выбирает сам, так как. это не те правила которые высечены в граните. Это просто рекомендации.
Переменные
Используйте enum для документирования
Enam'ы могут помочь документированию вашего кода. Например когда мы обеспокоены тем, что наши переменные отличаются от значений.
Плохо:
const GENRE = {
  ROMANTIC: 'romantic',
  DRAMA: 'drama',
  COMEDY: 'comedy',
  DOCUMENTARY: 'documentary',
}
projector.configureFilm(GENRE.COMEDY);
class Projector {
  // delactation of Projector
  configureFilm(genre) {
    switch (genre) {
      case GENRE.ROMANTIC:
        // some logic to be executed 
    }
  }
}Хорошо:
enum GENRE {
  ROMANTIC,
  DRAMA,
  COMEDY,
  DOCUMENTARY,
}
projector.configureFilm(GENRE.COMEDY);
class Projector {
  // delactation of Projector
  configureFilm(genre) {
    switch (genre) {
      case GENRE.ROMANTIC:
        // some logic to be executed 
    }
  }
}Функции
Избегайте проверки типов
TypeScript является надмножеством синтаксиса JavaScript и добавляют дополнительные статические проверки типов для языка. Всегда предпочитайте указывать типы переменных, параметров и возвращаемых значений, чтобы использовать всю мощь TypeScript. Это делает будущий рефакторинг более легким.
Плохо:
function travelToTexas(vehicle: Bicycle | Car) {
  if (vehicle instanceof Bicycle) {
    vehicle.pedal(currentLocation, new Location('texas'));
  } else if (vehicle instanceof Car) {
    vehicle.drive(currentLocation, new Location('texas'));
  }
}Хорошо:
type Vehicle = Bicycle | Car;
function travelToTexas(vehicle: Vehicle) {
  vehicle.move(currentLocation, new Location('texas'));
}Используйте итераторы и генераторы
Используйте генераторы и итераторы при работе с коллекциями данных, которые используются как поток.
Есть несколько причин для этого:
- отделяет вызываемый объект от реализации генератора в том смысле, что вызываемый объект решает сколько элементов
иметь для доступа - ленивое выполнение, элементы передаются по требованию
 - встроенная поддержка итерации элементов с использованием синтаксиса 
for-of - итераторы позволяют реализовать оптимизированные паттерны итераторов
 
Плохо:
function fibonacci(n: number): number[] {
  if (n === 1) return [0];
  if (n === 2) return [0, 1];
  const items: number[] = [0, 1];
  while (items.length < n) {
    items.push(items[items.length - 2] + items[items.length - 1]);
  }
  return items;
}
function print(n: number) {
  fibonacci(n).forEach(fib => console.log(fib));
}
// Print first 10 Fibonacci numbers.
print(10);Хорошо:
// Generates an infinite stream of Fibonacci numbers.
// The generator doesn't keep the array of all numbers.
function* fibonacci(): IterableIterator<number> {
  let [a, b] = [0, 1];
  while (true) {
    yield a;
    [a, b] = [b, a + b];
  }
}
function print(n: number) {
  let i = 0;
  for (const fib of fibonacci()) {
    if (i++ === n) break;  
    console.log(fib);
  }  
}
// Print first 10 Fibonacci numbers.
print(10);Существуют библиотеки, которые позволяют работать с итераторами так же, как и с собственными массивами, путем цепочка методов, таких как map, slice, forEach и др. Смотрите itiriri пример продвинутой манипуляции с итераторами (или itiriri-async для манипуляции с асинхронными итераторами).
import itiriri from 'itiriri';
function* fibonacci(): IterableIterator<number> {
  let [a, b] = [0, 1];
  while (true) {
    yield a;
    [a, b] = [b, a + b];
  }
}
itiriri(fibonacci())
  .take(10)
  .forEach(fib => console.log(fib));Объекты и структуры данных
Используйте геттеры и сеттеры
TypeScript поддерживает синтаксис геттеров и сеттеров. Использовать геттеры и сеттеры для доступа к данным объекта гораздо лучше, чем напрямую обращаться к его свойствам. "Почему?" спросите вы. Вот список причин:
- Если вы хотите реализовать больше, чем просто доступ к свойству, вам нужно поменять реализацию в одном месте, а не по всему коду
 - Валидацию легко реализовать на уровне реализации 
set - Инкапсуляция внутреннего состояния
 - Легко добавить логирование и обработку ошибок на уровне геттеров и сеттеров
 - Вы можете лениво подгружать свойства вашего объекта, например, с сервера
 
Плохо:
type BankAccount = {
  balance: number;
  // ...
}
const value = 100;
const account: BankAccount = {
  balance: 0,
  // ...
};
if (value < 0) {
  throw new Error('Cannot set negative balance.');
}
account.balance = value;Хорошо:
class BankAccount {
  private accountBalance: number = 0;
  get balance(): number {
    return this.accountBalance;
  }
  set balance(value: number) {
    if (value < 0) {
      throw new Error('Cannot set negative balance.');
    }
    this.accountBalance = value;
  }
  // ...
}
// Теперь `BankAccount` инкапсулирует логику проверки.
// Если однажды спецификации изменятся, и нам понадобится дополнительное правило проверки,
// нам придется изменить только реализацию `сеттера`,
// оставив весь зависимый код без изменений.
const account = new BankAccount();
account.balance = 100;Создавайте объекты с приватными/защищенными полями
TypeScript поддерживает public (по умолчанию), protected и private средства доступа к свойствам класса. 
Плохо:
class Circle {
  radius: number;
  constructor(radius: number) {
    this.radius = radius;
  }
  perimeter() {
    return 2 * Math.PI * this.radius;
  }
  surface() {
    return Math.PI * this.radius * this.radius;
  }
}Хорошо:
class Circle {
  constructor(private readonly radius: number) {
  }
  perimeter() {
    return 2 * Math.PI * this.radius;
  }
  surface() {
    return Math.PI * this.radius * this.radius;
  }
}Уважаемые читатели, а какими принципами вы пользуетесь при использовании TypeScript?
Продолжение следует...
          
 
miraage
Всё ниженаписанное подкреплено опытом написания немаленьких проектов с большим сроком поддержки и сменами с составе команды.
Я — евангелист строковых Enum. В статье, ключи отличаются от значений — я считаю это за абсолютно нереальный случай. Согласен, что так писать нельзя. И всё же:
1) Удобно дебажить (удачи в каких-нибудь React Devtools узнать значение в props, когда в Enum 20-30 значений)
2) Спокойно можно добавлять новые значения, менять местами (можно перзистить значения и спать спокойно, зная, что ничего не сломается)
3) Меньше размер бандла после компиляции (не катастрофа, но всё же)
Магические геттеры/сеттеры… Хочется вернуться в прошлое и не допустить их появление в JS.
Просто писать явно getSomething и setSomething.
Zoolander
Поддерживаю.
пп. 1 и 2 — бесценны.
Абсолютно непонятно, почему автор оригинального текста решил предпочесть числовые enum. Потом ему кто-то (или даже он сам) добавляет новый элемент в начало enum — и привет, все enum-проверки сломались.
JustDont
С учетом того, что в TS всё уже хорошо с discriminated unions, вам и строковые енумы нафиг не нужны. Зачем, когда то же самое сделает
Zoolander
покажите пример со switch или if
JustDont
Всё то же самое, что и с енумом. Да, у вас в коде явно будут написаны все эти 'foo' и 'bar' — но какая разница если это всё тайпчекается. Измените тип — компилятор этим сравнениям (и свичам) даст отлуп и потребует их поменять. Так же, как если вы значение енума переименуете.
Zoolander
Хорошо.Но есть нюанс
дает более полное представление о контексте применения кода, чем
Хотя бы потому, что романтическим может быть что угодно — от девушек до самолётов.
JustDont
Какое еще «более полное представление» вам нужно? Бороться с duck typing в JS/TS не имеет ни малейшего смысла.
Zoolander
я вас не критикую. Вы можете писать как угодно.
Обилие строковых литералов в коде на мой взгляд неудобно.
В последнем комментарии я имел в виду читабельность кода. Мы смотрим на коммит, там изменилась одна строчка. По выбранному enum мы видим и понимаем смысл кода быстрее, чем просто по строковому литералу.
Если вы читаете мало коммитов, для вас это может быть не актуально.
amakhrov
Умный поиск/рефакторинг в IDE гораздо лучше работает с явным enum, чем со строковыми константами.
Со строковыми литералами компилятор, конечно, выдаст ошибку, если рефакторинг был произведен некорректно. Но с enum рефакторинг просто сразу будет корректным.