Как стать автором
Обновить

Комментарии 26

Спасибо за статью. TS нынче это вообще единственный выход для неTDD-разработки чего-нибудь немаленького на фронте. И чем больше людей смогут в типы, тем лучше; меньше будут брать TS и писать потом any везде, где типы сложные.
ещё dart есть. мне нравится.

Кстати, а есть простая возможность включать strict на уровне файла? Ну или включить на проекте и выключать на уровне файла?

Это ж на уровне линтера идёт, т.е. можно второе — глобально включить, а локально делать игнор правила, если очень хочется.

Разве линтера? По крайней мере, собственно параметр strict — это параметр typescript, а не tslint. А в typescript можно ли локально игнорировать определённые правила? Для произвольной ошибки — да, есть // @ts-ignore, а для конкретной проверки?

Да, пардон, перепутал с другими вещами. Вы всё верно пишете. И ts-ignore не умеет в конкретику. Пока что разбить код на strict и не strict можно только через два разных вызова компилятора.
@ts-ignore используется и для tcm и для линтеров
пожалуйста перестаньте использовать ts-lint и переходите на eslint с плагинами для тайпскрипт. сразу почувствуете разницу в лучшую сторону. для eslint удобно отключать правила как глобально так и локально.
Не критикую, просто интересуюсь.
function getUserType(id: number): string { /*… */ }

function getUserType(id: number): 'standard' | 'premium' | 'admin' { /*… */ }

Вы пишете, что вторая функция лучше, так как более информативна. Но что делать, если (когда) добавится новый тип юзеров, 'banned', например? Ходить по всем таким функциям и исправлять?
А если мы пишем аналогичные функции getUserCountryName и getUserCurrencyCode — тоже в них все 150 возможных ответов перечислять?

Можно тип объявить. Я думаю, автор написал инлайн-объявление просто для примера.

Если тип используется больше одного раза, то можно определить для него «алиас»:
export type UserType='standard' | 'premium' | 'admin' ;


тогда объявление функции приобретет такой вид:
function getUserType(id: number):UserType { /*… */ }


А если мы пишем аналогичные функции getUserCountryName и getUserCurrencyCode — тоже в них все 150 возможных ответов перечислять?


тут тип возвращаемого функцией значения скорее всего будет просто «string»
но если вы хотите чётко проверять на опечатки — то можно перечислять хоть 100500, в зависимости от того насколько критична определённая часть кода
А если мы пишем аналогичные функции getUserCountryName и getUserCurrencyCode — тоже в них все 150 возможных ответов перечислять?


Тут зависит от ситуации.

enum CountryCodeEnum {
    US = 'US',
    // ...
    RU = 'RU',
}

enum UserTypeEnum {
    STANDARD = 'standard',
    PREMIUM = 'premium',
    ADMIN = 'admin'
}

interface IUser {
    id: number;
    name: string;
    age: number;
    type: UserTypeEnum;
    country: CountryCodeEnum;
}


function getCountryCode(user: IUser): CountryCodeEnum {
    return user.country;
}


В комментариях к оригинальной статье автору советуют использовать enum для подобных случаев: https://dev.to/lexlohr/comment/d831

лучше использовать const enum. Но вроде бы, это не совместимо с babel (sic) транспайлером.
вы правы, бабел транспайлер не поддерживает enum, namespace и `export =`

я столкнулся с этим в проектах на gatsby.js
1. Используйте type alias:
export type UserType = 'standard' | 'premium' | 'admin'

Также хорошая альтернатива — string enum:
export enum UserType { Standard = 'standard' /*...*/ }

2. Это немного другой сценарий — очень много вариантов. Например, зачастую конкретные currencyCode при этом просто не используются — все приходит с сервера или выбирается юзером. Но если они все таки нужны, можно решить проблему константами, например ввести DEFAULT_CURRENCY_CODE для предзаполнения дропдауна. Система типов для этого полезна, но не является оптимальным решением.

Вот только сегодня доработал этот подход, способом возможным с, кажется, 3.4:


// possible values
const statuses = ["new", "approving", "approved", "published", "depublished"] as const;
// pseudo-enum 
export type Status = typeof statuses[number];
// type guard
export const isStatus = (value: any): value is Status => (
  typeof value === 'string' && statuses.some(status => status === value)
);

Эта штука в первой строчке была :)

По поводу документирования функции. Если она правильно оформлена с указанием входящих и исходящих типов данных, то она уже является самодокументированной — зачем тратить время на многострочное описание того, что грамотный разработчик прочтет в самой функции?
Многострочное описание — не нужно. Но коротко описать важные детали реализации бывает полезно:

  • читать код реализации функции может быть довольно утомительно просто в силу объема
  • по деталям реализации может быть не совсем понятно, что именно делает функция
  • подобное описание может использоваться для генерации документации
  • значит функция недостаточно декомпозирована
  • это должно быть понятно из её имени
  • вот тут согласен, правда некоторые средства генерации документации иногда ведут себя странно, игнорируют фактическую сигнатуру функции, перекрывая её тем, что описано в в doc. Почему я от них отказался для внутренних разработок. *doc должен дополнять код, а не переопределять его.

В любом случае плохо бросаться

значит функция недостаточно декомпозирована

Я не очень понял как декомпозиция сделает поведение функции более понятно


notSimpleFunction (someArg) {
  // A lot of code
}

станет


notSimpleFunction(someArg) {
  // firstSimpleFunction(someArg)
  // realyEasyFunction(someArg[1])
  // makeItEasy()
}

код функции может и станет проще понять, но ее поведение (то есть что она возвращает от принятых данных) понять проще не станет

Во втором случае перестаёт работать "читать код реализации функции может быть довольно утомительно", ведь прочесть три строчки ни разу не утомительно.

Если их называть first, easy и т. п., то сильно проще понять не станет, да :)

*Типы — это документация* — плохой пример, комментарии загрязняют код и им свойственно устаревать. Метод должен описывать сам себя через имя и типы, да типы чтобы войти в тип и посмотреть, из чего он состоит, а не читать коментарии.
Зарегистрируйтесь на Хабре, чтобы оставить комментарий

Публикации

Истории