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

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

О, круть будем ждать релиза, в ФП кстаки есть функция которая выполняет роль NeverError называется absurd: <A>(x: never) => A. Вот мой вариант этого ts хелпера

public beforeAccessHook(this: never)

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


В таких случаях следует использовать null.


Я думал, что с помощью never могу управлять обязательностью параметров функций и при определенных условий отключать ненужные.

Та же самая ошибка: never не является отсутствием параметра, это отсутствие возможных значений параметра.

это всё хорошо конечно, но если есть кто-то кто только что понял всю суть тс… объясните пожалуйста.
Вопрос короткий: «зачем писать лишний код, с заведомо явным поведением?»
Каждый раз когда спрашиваю тайпскриптеров про такого вида «театр безопасности», слышу вот ответ одни отмашки =/
Вопрос короткий: «зачем писать лишний код, с заведомо явным поведением?»

Незачем, никто и не пишет. При чем тут тс?

Вопрос явно провокационный, но я попробую ответить.
1. Это как ремень безопасности. Нужно совершать «лишние» действия, каждый раз в надежде что это хоть раз пригодится. Кто-то использует, а кто-то нет. Но статистика — твердолобая штука, и говорит что те кто с ремнём — выживают. И далее, когда вы знаете что в безопасности, то можете двигаться быстрее. А по тропе у обрыва вы будете двигаться гораздо медленнее и более осторожно, тратить дополнительные нервы на это.

2. Про заведомо явное поведение. Одно дело явное поведение, а другое — явная декларация этого поведения в интерфейсе, и уверенность в строгом соблюдении этой декларации. На маленьком проекте это кажется ненужным и бесполезным. А на большом (например в моём тайпскрипт проекте сейчас 3500 файлов и пол миллиона строк кода, публиковал статистику тут habr.com/ru/company/directum/blog/462055/#comment_20464837) вам важно бегло ориентироваться по интерфейсам. На большом проекте никто и никогда не может знать как работает весь код. С ростом кодовой базы затраты на чтение и понимание кода вокруг всё растут и превышают затраты на написание дополнительных деклараций. И, нужно сказать, что написание интерфейсов и деклараций в реальности не так уж и много времени отнимает, и лично для меня, за счёт корректной работы подсказчика, кратно повышает скорость написания кода. И последнее про скорость, на самом деле скорость набора кода почти ни на что не влияет. Основное время уходит на чтение кода, архитектуру, дебаг, обслуживание этого кода, обучение коллег и т.п. Именно сам фигачинг и потоковый набор кода — не такой уж и большой процент времени программиста занимает.

И кстати, отдельно про тайпскрипт и безопасность. Он легко позволяет безопасность нарушать там где этого хочется. И это прекрасно. Всё не абсолютно строго, и если ты понимаешь что ты хочешь, то ты можешь лавировать в этих джунглях ограничений порой выруливая абсолютно сложные и неразрешимые проблемы в более строгих языках. Я бы назвал это строгостью по запросу. Мне нужна безопасность, инструмент даёт её мне. Я хочу выстрелить между пальцев ноги, и я элементарно снимаю защиту от стрельбы в ногу и стреляю. Если я всё правильно посчитал, то выстрел меж пальцев прекрасно удаётся, если нет — мне оторвёт ногу. Я откачу ревизию и подумаю получше. Этот подход как обоюдоострый меч требует ответственности и вкуса от пользователя, но открывает возможности возлагая ответственность.
И ещё, если вы не замечаете, то тайпскрипт идёт по пути не только создания инструментов безопасного написания кода, но и так чтобы инструменты безопасности не были навязчивыми. Автовыведение типов, flow analysis и многое другое ведёт к тому что код становится более чистым но столь же типизированным. Они планомерно уходят от необходимости лишний раз описывать те типы который и так можно вывести, и надо сказать что уже очень сильно продвинулись.
Абсолютно незачем, вы правы. TypeScript это один из самых мерзотнейших идиотизмов, придуманных кодерами, которым, походу, было нечем заняться.

Все эти тонны говнокода решают проблемы которые сами же и придумывают.

А в больших проектах отнимают прорву времени на совершенно бесполезное описание типов и такой же бесполезный формализм.

Поменялось ли ваше мнение за три года?)

Вы знаете, поменялось, но не кардинально.

Я всё ещё считаю тайпскрипт гадостью, но теперь, поработав в реально больших проектах понимаю его плюсы для больших команд и большой кодовой базы.

Так что да, что касается больших проектов я был не прав.

Ок, понятно, спасибо за ответ)

Я не знаком с TypeScript, но тема крайне интересная.
Смысл типа never вполне понятен — в некоторых языках есть что-то типа «noreturn» (тип или спецификатор), это используется оптимизаторами.
Но вот непонятно, чем тип never в системе типов и при использовании в качестве параметра шаблонов лучше чем какой нибудь void? Т.е. ясно что это разные вещи, но вот как именно never влияет на шаблонный код?

void может иметь значение undefined (и, строго говоря, больше ничего), то есть просто означает, что вычисления дошли до соответствующей строчки кода. never значения иметь не может вообще — т.е. обозначает, напротив, некоторый недостижимый код.

Уточнение: в Typescript void может принимать два значения, undefined и null.

Ну я спрашивал не про typescript, а вообще.
А то что void может принимать два значения это уже какой-то нонсенс:) (хотя наверное понятно почему так, но все-же это из разряда языковых курьезов, которые во всех языках программирования бывают)
Уточнение: в Typescript void может принимать два значения, undefined и null.

null может только без strictNullCheck'а, но без него абсолютно все типы nullable, т.е. по факту void это только undefined.


И даже для undefined к этому утверждению надо относиться с осторожностью — хотя undefined assignable to void, тип undefined не является подтипом типа void.

после заключения должна быть картинка с Риком Эстли
Благодарю за работу, как раз сегодня пригодился прием из статьи.
Вряд ли я бы его использовал до нее :)
Всегда пожалуйста :)

Какой прием, если не секрет?

Не нашёл в статье самого для меня используемого способа: запрещать передавать определённое свойство в интерфейс.


Так как типизация у нас структурная, если при присвоении/передаче в объекте находится больше свойств, чем того требует принимаемый интерфейс, всё будет ок.


Однако, если это не приемлемо, и от передачи каких-то свойств нужно обезопаситься, можно объявить их в интерфейсе опциональными и с типом never, вот так.


Юзкейс из реакта: запретить передавать компоненту children, явно показав, что содержимое не будет использовано:


FC<{ children?: never }>
Спасибо, действительно хорошее дополнение для статьи. В продолжение — попробовал добавить тип, который допускает передачу только объектов того же типа.
type OneField = {
    id: string;
}
type TwoField = {
    id: string;
    data?: string;
}

type DiffType<Free, Strong> = Omit<Free, keyof Strong>
type Constraint<Free, Strong> = Record<keyof DiffType<Free, Strong>, never>
type DirectType<Free, Strong> = Free & Constraint<Free, Strong>

function validate<Free>(data: DirectType<Free, OneField>) {
    // do some work
}

const okData: OneField = null;
const badData: TwoField = null;

validate(okData);
validate(badData); // Ошибка!!!
validate<OneField>(badData); // Должно работать :-)
Да, а еще так :)
validate(<OneField> badData)
validate(badData as OneField)


К сожалению, я не нашел способа запретить указание дженерика
Пример с ActionEngine — настолько же бесполезное высосанное из пальца дерьмо, как и весь TypeScript.

Смысл всей это писанины лишь в том, чтобы на этапе компиляции обратить внимание, что где-то в свитч приходит какой-то тип экшона, который свитчом не предусмотрен.

Самая дурь ситуации, что пример приводится для случая, когда варианты экшонов описаны не в проекте, а где-то вовсе снаружи. То есть, по сути, на этапе компиляции-то как раз данная ошибка никак возникнуть не может.
Зарегистрируйтесь на Хабре, чтобы оставить комментарий

Публикации

Истории