A: Не думай о помощи.
Б: Сложно не думать о помощи, когда пишешь на javascript.
Примерно такой диалог я слышал на одной из конференции. Решить проблему отсутствия строгой типизации был призван typescript.
Конкретно в этой статье я хотел бы рассмотреть один из приемов использования интерфейсов typescript, который мне кажется неочевидным, его я подсмотрел и смог оценить его преимущества в процессе написания приложений на языке golang.
Для большинства typescript разработчиков типы и интерфейсы, не имеют как таковой большой разницы.
type Dog = {name: string, age: number}
interface Dog {
name: string,
age: number
}
И запись при помощи интерфейса и при помощи типа по своей сути равнозначно смогут дальше работать, и подсказывать ошибки типизации при дальнейшей разработке
Что я предлагаю?
Я предлагаю разделять эти 2 понятия:
Типы используем когда хотим описать определенные атрибуты объектов.
Интерфейсы когда хотим описать поведение объектов, их методы.
Для начала создадим интерфейс “greeter”.
interface greeter {
greet() : void;
}
Создадим типы “Dog” и “Cat”.
type Dog = {name: string, age: number}
type Cat = {first_name: string, second_name: string, owner: string}
Как мы видим эти типы, имеют различные наборы атрибутов.
Далее создадим функцию, которая принимает в качестве первого аргумента, объект удовлетворяющий интерфейсу “greeter” и далее вызывает его метод “greet”.
function greet(g: greeter) {
g.greet();
}
Что-бы наши типы “Dog” и “Cat”, можно было использовать при вызове функции “greet”, необходимо явно объединить типы “Dog” и “Cat” c интерфейсом “greeter”
type Dog = {name: string, age: number} & greeter
type Cat = {first_name: string, second_name: string, owner: string} & greeter
Реализуем объект каждого типа
const dog: Dog = {
name: "jack",
age: 10,
greet() {
console.log(`hello im dog. My name is ${this.name}. I'm ${this.age} years old.`)
}
}
const cat: Cat = {
first_name: "Myley",
second_name: "Meows",
owner: "Ivan",
greet() {
console.log(`hello im cat. My name is ${this.first_name} ${this.second_name}. My owner name is ${this.owner}`);
}
}
Что мы имеем? У нас 2 объекта, разные по своей реализации, но их объединяет наличие метода, указанного в интерфейсе “greeter”
Вызовем эти методы
greet(dog);//"hello im dog. My name is jack. I'm 10 years old."
greet(cat);//"hello im cat. My name is Myley Meows. My owner name is Ivan"
Итог:
Интерфейсы позволяют разделять реализацию от так называемого слоя бизнеса.
Например с точки зрения реализации пользователя и администратора в рамках одного приложения, они могут иметь различный набор атрибутов. Но в конце концов для их создания, нужно использовать один и тот же хендлер бекенда.
Код становится чище и в результате более легким для восприятия.
Позволяет разделять приложения, на более мелкие, независимые слои.
Комментарии (88)
wdhappyk
22.04.2024 14:28+5Данный подход не совсем уместен, так как связывает руки в ряде случаев. Основное отличие интерфейса от типа в том, что интерфейс по сути является partial и мы можем расширить его нужной структурой не прибегая к оберткам и дополнительным типам. А типы в свою очередь поддерживают вычисления и типы-суммы.
Мы в работе используем иной подход разделения, когда контракты объектов данных и сервисов представляют из себя интерфейс, а типы используются для утилитарных, существующих только на клиентской части элементов, так как использование union и прочих сложных вычислений над типами сложно повторить в других ЯП (ОО). И конечно там, где функциональность интерфейсов не важна.
meonsou
22.04.2024 14:28+2Нет никакого смысла разделять интерфейсы и типы концептуально, потому как разница между ними сугубо практическая. Пренебрежение их практическими свойствами в угоду какому-то выдуманному разделению неминуемо приведёт к ошибкам.
aamonster
22.04.2024 14:28Множественное наследование от интерфейсов безболезненно, множественное наследование от типов тянет за собой ряд проблем.
ArthurG
22.04.2024 14:28Спасибо за статью!
В интерфейсах есть баг в TS, лучше определять функции в полях, а не методы.
Интерфейсы позволяют скрыть содержимое типа при выводе в редакторе, что улучшает чтение кода. Поэтому, я считаю, у интерфейсов гораздо больше применения.
meonsou
22.04.2024 14:28В интерфейсах есть баг в TS, лучше определять функции в полях, а не методы.
Что за баг?
ArthurG
22.04.2024 14:28В методах плохая проверка типов аргументов.
meonsou
22.04.2024 14:28Так это не баг, это by design у них. Так сделано чтобы привычные практики из жса у людей не ломались.
During development of this feature, we discovered a large number of inherently unsafe class hierarchies, including some in the DOM. Because of this, [strict function types] only applies to functions written in function syntax, not to those in method syntax.
Alexandroppolus
22.04.2024 14:28Если речь об этом, то такая проблема не только в интерфейсах, но и в типах и даже, как ни прискорбно, в классах
KataevAS
22.04.2024 14:28+1Весь пример из статьи можно полностью написать на inteface и так же полностью на type. Правильно я понимаю, что Вы не предлагаете разбираться чем же все-таки они отличаются, а предлагаете соглашение для дополнительного смыслового разделения? Тогда вопрос такой - что Вам мешает использовать type для описания поведения объектов и их методов и продолжать все так же разделять исходный код на:
... определенные атрибуты объектов.
... поведение объектов, их методы.
Интерфейсы позволяют разделять реализацию от так называемого слоя бизнеса.
Получается, что type тоже это позволяет?
Ощущение, что статья больше не про применение interface (особенно удобного в ООП) и type, а про разделение сборки свойств объектов.
AidarNasibullin Автор
22.04.2024 14:28Да действительно, все можно написать и на типах и на интерфейсах,интерфейсы позволяют не привязываться к конкретной реализации чего либо. Если я правильно Вас понял, при использовании например типов, придется писать адаптеры, которые будут приводить конкретную реализацию, к типу, который необходим конкретной функции.
DiegoV
Добро пожаловать в C#...
Когда-нибудь javascript разработчики поймут, что хватит стрелять себе в колени, все давно придумали за них и героически изобретут SharpScript
19Zb84
AsemblerScript уже есть.
Написанеие кода на java script позволяет писаить на любом практичесуки языке где есть wasm.
Все зависит от задачи.
Не видел еще проектов, крооме блокчейнов где type sacript был бы прямо неоьходим.
bromzh
Ну ничто не необходимо, так-то можно и на бэке всё на ассемблере писать или сразу в машкодах. Типизация это просто вопрос удобства разработки и уменьшения проблем до запуска программы.
Попробуйте порефакторить любой большой js проект. Например, есть 2 эндпоинта
/api/user
и/api/item
. Они возвращают схожие объекты с полем name: `{ id: 1, name: 'name', ... }`. Далее, эти данные разлетаются по всему приложению на сотню различных страниц. Теперь мы хотим переименоватьname
вfullName
для юзера, но оставитьname
у item нетронутым. Typescript позволит сразу увидеть, где мы используем старое поле и где нужно его сменить (Ну и чем больше описано типов, тем проще что-то добавлять или изменять). Для js же обычно всё вылезет в рантайме.19Zb84
Скорость стайп скриптом падает раза в три
Как минимум имз за того что раза в три больше кода писать надо.
Я бы стейт сделал из которого брал данные.
Задача легко решается изменением одного объекта и посмотреть где данные из стейта используются. Не особо проблема. С type script тоже самое делать придееется... но я давно не видел сайты на 100 страниц.
Как паравило это небольшие сервисы соединенные вместе.
Lainhard
Низкая скорость написания с лихвой компенсируется скоростью/сложностью рефакторинга.
19Zb84
Как может наличие типов повлиять на скорость рефакторинга ?
Например.
У вас было 5 методов, которые вы решили объединить в один модуль и обращаться к нему из всего приложения.
* Сделать модуль и подключить в него все методы.
* Создавать модуль, создавать типы с которыми он работает, создавать новые интерфейсы для методов, если параметры поменяются.
Где тут ускорение рефакторинга ?
Тем более если определенные части кода должны иметь строгую типизацию, то в чем проблема написать эти части кода с использованием type script и жить спокойно ?
А если хочется по каким то причинам использовать типы, в чем проблема настроить статическую типизацию с jsdoc например и так же спокойно писать код так же как и с type script.
bromzh
Так я рефакторю typescript-проект, у меня типы уже есть.
Это не так работает. Меняются параметры функции -> тайпскрипт выводит сигнатуру этой функции -> автоматом проверяет, все ли использования этой функции корректны. Если я где-то забыл перейти на новую сигнатуру у меня просто выскочит ошибка с указанием места.
Теперь перейдём в мир js. Что там будет, если поменять сигнатуру функции? Да ничего, если вы забудете где-то поменять параметры, то об этом узнаете только в рантайме. Повезёт, если сразу станет понятно проблемное место.
Если же меняется структура данных, которыми манипулирует функция, т.е. интерфейсы, то их поправить занимает не так много времени. При этом опять же, тс сразу покажет, где эти типы используются и
Рефакторинг - это не только изменение кода, но и проверка на корректность. Изменение кода обычно быстрее, так как я сразу вижу всё что нужно исправить. Проверка тоже быстрее, потому что часть глупых ошибок, типа "забыл изменить имя поля, забыл добавить второй параметр в функцию, опечатался в названии" просто исчезают навсегда. Пример я приводил - поменять поле name в одной структуре, не трогая другую. Простым поиском и заменой тут дело не решишь. Могу ещё примеров накидать
Противники типизации никак не могут понять, что они тоже в конечном итоге работают с типами, потому что данные, которыми манипулируют не рандомные, а имеют какую-то структуру. Только вот типы у них "вылазят" в самый последний момент, когда их уже используют. Но из-за динамичности языка где-то на пути от, условно получения из апи до вывода на экран, какие-то типы могут быть неправильно преобразованы или использованы. Тайпскрипт просто позволяет выявить это раньше, до запуска.
Это как писать программу по ТЗ. JS - это устные договорённости, которые все забывают или искажают, неверно интерпретируют (потому что описано размыто). Поэтому нужный результат долго получается - слишком много доделок. TS - это нормальное ТЗ записанное в условном конфлюенсе, где всё оговорено, где пограничные случаи описаны, так что ты просто читаешь и пишешь. Мне вот по второму способу удобнее и быстрее работать.
ijustwanttobeacool
Сначала вы говорите
А потом вы пишете
Действительно...
Я в своё время пытался сделать проект с использованием jsdoc и это боль, когда проект становится хоть сколько-нибудь большим
bromzh
Сочувствую. В моём тайпскрипте по-другому.
Берите больше, в 10 раз!
Я вот код больше читаю/исправляю, чем пишу. Писать мне всякие AI-ассистенты и IDE помогают. А вот время на поиск глупых ошибок, вроде опечаток имени полей в рантайме, почему-то противники тайпскрипта не учитывают. Видимо они реально только пишут код, но не сопровождают его.
19Zb84
Я в этом году поддерживал 5 проектов, которые сам спроектировал и написал.
Знаю о чем говорю.
Судя по минусам, это самое токсичное сообщество из всех которые я только видел.
Слава богу что с такими людьми не приходилось работать... А если и были, в реальной жизни как то так лихо минусы не получается ставить при личном разговоре.
Обидно что из за некчемной статьи, какие то люди с достаточно низким интелектом, испортили карму. Напиши парень мне, я тебе в личку напишу что я о тебе думаю.
doctorw
Как долго вы поддерживали эти 5 проектов и какого рода поддержку выполняли?
19Zb84
В течении уже 2-х лет. Они со своими проблемами.
Но деплой 400 миллесекунд
Отсутсвие всех лишних зависимостей.
Соусры запскаются без всяких бандлеров и все сервисы при желании можно объединить в один проект и либо сделать разделами либо динамически подгружать.
Все четко работает.
Минус тайп скрипта в том, что он половину плюсов моего проекта убьет своей компиляцией. + я не видел ни одного стоящего проекта написанного на type script (Исключение только уже очень матерые проекты, где уже вся остальная работа сделана)
Type Script к себе в проект добавить это дело 1 часа с перекурами.
Тема статьи тем отличается типы от интерфейсов.
Здешние шавки вместо того что бы подумать об этом, повторяют где то прочитанные фразы, не пытаясь даже понять что прочитали и как это связанно с темой статьи.
Я этот аккаунт удалю завтра после завтра....ТОчно с фронтен разработчиками которые кричат про тайп скрипт даже смотреть на них не буду ни то что разговаривать.
doctorw
Вы употребляете фразы вроде "Здешние шавки", делаете категоричные заявления, и жалуетесь, что вас минусуют? Вы странный.
Что касается проекта, который вы поддерживали в течение 2-х лет и деплоящийся за 400 мс, то складывается впечатление, что это не серьёзный проект, а одностраничник с парой кнопок. А сколько релизов было за эти 2 года?
На серьёзных проектах, проблемы начинают ощущаться на горизонте либо 5 лет либо при интенсивной разработке уже до 5 лет. Либо вы помимо этого проекта должны заниматься ещё минимум 3-4 проектами, чтобы в голове не умещалась вся модель оного.
DEugene
Мне кажется это закономерно. Вы без тени сомнения делаете голословные и категоричные заявления. Перечеркиваете всю пользу теории типов, материализованную в TS.
19Zb84
Мне кажется это закономерно. Вы без тени сомнения делаете голословные и категоричные заявления. Перечеркиваете всю пользу теории типов, материализованную в TS.
Я не перечеркиваю теорию типов.
Я против того, что бы люди не имея представления зачем это нужно кричали громче всех что без этого писать невозможно.
Факт Это в 90 % кода на фронте не имеет смысла.
Ни одного аргумента в пользу тайп скрипта тут ещё не сказал, что бы можно было сказать что это да.
doctorw
Если вы не собираетесь заниматься поддержкой проекта в перспективе 5-10 лет или получить по лбу от тех, кто будет заниматься поддержкой проекта после вас, то стоит использовать TS.
А если вы пишете write-only код для proof-of-concept, то конечно можно и JS обойтись.
kellas
Я занимаю веб-разработкой больше 15 лет уже , в основном фронтендом и полностью с вами согласен. TS тот еще костыль. Не обращайте внимания на этих "разработчиков" они озабочены по большому счету только своим комфортом и у них совершенно другие приоритеты и подход к работе, c TS лично им приятнее ковыряться в IDE, они чувствуют себя умными, а не идиотами которые не могут отдебажить элементарные вещи, это не они платят за увеличение сроков разработки а им, так что их даже можно понять )
bromzh
Я тоже знавал таких разрабов, ярых противников TS. Очень горды тем, что пишут на том самом js. Очень горды тем, что им типы нафиг не нужны. И обычно они работают одни, пилят прототипы, которые не будут поддерживать никто, либо пилят свои проекты в одиночку, потому что уровень велосипедства там такой, что никто больше не разберётся. Не все, конечно, но большинство такие.
Самое смешное, они реально думают, что тайпскриптеры целыми днями сидят и типы свои пишут, вместо работы. Напоминают пожилых людей, которые не разбираются в компухтерах и ругают айтишников в духе "кнопки свои нажимает, штаны просиживает, лучше бы делом занялся".
Высокомерный мем внутри
kellas
А почему никто больше не разберётся? И как люди разбирались со сложными проектам типа визуальных конструкторов сайтов до появления TS? Как же смогли написать github , tilda(вообще кажется на jQuery), vkontakte без тайпскрипта?
У меня почти все проекты на работе на TS и я прекрасно вижу какой ценой достигается это "удобство" и "понятность". Код пишется дольше, читается дольше и работает хуже по всем метрикам . Тесты писать всё равно приходится , иначе баги лезут, а эти тесты и без TS могу поверить что где-то не те данные приходят.
bromzh
Ну вы обобщаете, про идиотов, сроки и дебаг, я вот тоже обобщаю. Я говорил про конкретную касту "отрицальщиков типов", с которыми я лично работал. Они обычно гордятся своим незнанием, любят делать запутанные штуки, используют динамические возможности JS во зло, скажем так. При этом есть огромная куча хороших проектов на чистом JS, которые понятны и хорошо работают.
Конечно можно верить во всемирный заговор Microsoft по созданию TS, как инструмента для затягивания сроков и увеличения бюджетов. А можно задуматься, а почему с TS у вас код даже работает хуже, хотя по-факту это надмножество языка. TS создавался с целью помочь программистам. Если же вы с ним боретесь, то вероятно надо повысить экспертизу в команде, например. Know your instrument, как говорится. Причем, в отличие от других языков, тут можно задавать уровень точности компилятора, и в случае затруднений точечно избегать типизации. Можно обходиться только простыми интерфейсами, без дженериков и всяких advaced types, чисто для дополнительной помощи в IDE. А можно проинвестировать в знания и фигачить всё на максималках, с большим трудом, но и с большими гарантиями и большим профитом по итогу.
В конце концов, я предпочту, чтобы за меня всякой рутиной по проверке корректности данных занимались проклятые роботы, а я уж логику буду писать и тестировать именно её, а не писать тесты на то чтобы в функцию какую-то фигню не передали.
19Zb84
Скорость с тайп скриптом падает раза в три
Как минимум имз за того что раза в три больше кода писать надо.
Я бы стейт сделал из которого брал данные.
Задача легко решается изменением одного объекта и посмотреть где данные из стейта используются. Не особо проблема. С type script тоже самое делать придееется... но я давно не видел сайты на 100 страниц.
Как паравило это небольшие сервисы соединенные вместе.
flancer
JSDoc позволяет сделать то же самое.
nin-jin
..путём написания раз в 10 больше кода, чем с TS.
flancer
зато без транспиляции :)
nin-jin
Ну-ну, вы и на прод все эти килотонны комментариев повезёте?
flancer
А у вас есть статистика на сколько килотонна комментов замедляет работу программы? А на сколько увеличивает скорость отлова багов? И, да - я потяну все эти килотонны на прод :) А вы можете их вырезать, если они вам не нужны. И всё равно без транспиляции;)
19Zb84
А у вас есть статистика на сколько килотонна комментов замедляет работу программы?
Вы гений. Задали вопрос и сами на него ответили.
bromzh
То есть фактически без проверок на ошибки, потому что ломаный код всё равно можно запустить.
flancer
А TS даёт 100% гарантию запускаемости кода? Или только повышает вероятность? Пишите прямой код, и не пишите кривой - вот и не будет ломанного кода. JSDoc'и лишь помогают IDE помогать вам ориентироваться в вашем коде - т.е., "сразу увидеть, где мы используем старое поле и где нужно его сменить".
bromzh
TS не даст скомпилироваться некорректному коду. Когда вся кодовая база на нём надо очень постараться, чтобы скомпилировать код с ошибками. На этом шаге надо призадуматься, а точно ли оно надо? Что нужно сделать, чтобы запустить ломаный код с JSDoc?
node index.js
и всё.А TS позволяет описывать контракты и всякие иварианты. Что позволяет сузить количество проблемных мест.
flancer
Успешное компилирование кода в TS говорит лишь о том, что в коде нет ошибок компиляции. А вот насколько хорошо тот код будет работать, то вопрос открытый. Я бы сравнил разработку на TS с занятием сексом в презервативе - он обязателен, если я не уверен в своих партнёрах. Или в себе.
doctorw
Нет ошибок компиляции, говорит о том, что в рамках того, что способен проверить компилятор - типы данных согласованы. Если писать на статически типизированном языке игнорируя типы, то толку конечно не будет, но если использовать систему типов по прямому назначению, то можно отсеять некоторые классы ошибок уже на этапе компиляции.
bromzh
Я понял, вы просто сразу пишете программы без ошибок. Всем бы так
doctorw
Без ошибок компиляции – да, если речь о коде, который попадает в remote branch. Я думаю о бизнес-логике, а о том, чтобы я не передал метры, там где ожидаются футы - заботится компилятор.
flancer
Это заблуждение.
https://overclockers.ru/blog/amv212/show/62908/oshibka-nasa-stoila-agentstvu-dorogostoyaschego-kosmicheskogo-apparata-dlya-issledovaniya-marsa-v-125-mln
doctorw
Это проблема границ кодовой базы, там где она соприкасается с другой кодовой базой посредством API. Если код на разных языках или API использует сериализацию, то такое компилятор естественно не найдёт. Однако, в пределах одной кодовой базы компилятор проверит согласованность.
Согласованность API между кодовыми базами – всегда было и остаётся обязанностью разработчиков.
С компилятором мне достаточно проверить только стыки, это заметно проще, чем надеяться, что я ничего не упустил в рамках всей базы.
bromzh
Ну я тоже) Я отвечал мистеру @flancer, который как бы доверяет себе и партнёру, но типы всё-равно везде ставит, просто в менее удобном и менее мощном виде.
flancer
... и в менее сковывающем движения :)
bromzh
Я просто боюсь, что так сильно распущусь, что тоже начну в конструкторе методы объявлять. Это вы свободный человек, а меня за такой код из всех моих галер выкинут(
flancer
Сочувствую :( Лично я не вижу в этом ничего плохого. Но я и не на галерах.
doctorw
del
doctorw
А в чём проблема транспиляции?
flancer
В неожиданности - код с которым ты имел дело в IDE, совсем не похож на тот код, который ты видишь на проде. Если что, я полтора года писал код с использованием GWT.
19Zb84
..путём написания раз в 10 больше кода, чем с TS.
Там вообще ничего не надо писать кроме коментариев с описанием типов.
bromzh
Вот вам пример кода от адепта типов в JsDoc. В тайпскрипте строчек будет поменьше, если вас так пугает количество букв. Как минимум,
/** @type {
заменяется на:
.flancer
Спасибо, что привели в пример :) Так-то я макросы использую. Нажимаешь горячую клавишу и вся комбинация `/** @type {} */` автоматом рисуется. Многословно? Пожалуй. Зато без транспиляции ;) Дебажить в браузере - одно удовольствие!
doctorw
Вы боитесь транспиляции, как я понял. Почему?
flancer
Ответил выше. Я не пишу код без ошибок, я просто их быстро нахожу.
aamonster
Ну ok. Не так важно, как именно внедрена типизация, лишь бы она была)
bromzh
Всё-таки важно. Она должна быть удобной (чтобы ты ей пользовался, а не избегал) и обязательной (иначе в один момент просто забудешь запускать проверки).
aamonster
Необходим – не скажу, но я помню, какое счастье было, когда js-часть нашего проекта перевели на ts. Стало на порядок легче жить.
bromzh
Зачем? Уже есть typescript. Система типов там ощутимо лучше C#. Некоторых языковых фич C# может и не хватает, но не так чтобы прям критично.
GospodinKolhoznik
Система типов typescript более менее неплохая. Проблема только том, что компилятор typescript зачастую в упор не видит несоответствия типов в выражениях при чуть более сложных типах, чем тривиальные. Что сводит на нет преимущества типизации.
bromzh
Можно пример?
olivera507224
Предположу, что человек имел ввиду отсутствие номинальной системы типов в TS. Проблема действительно есть, но преимущества типизации она, конечно же, на нет ни в коем разе не сводит. Где-то читал, что номинальную систему в будущем всё же хотят ввести. Сейчас проблема частично решается брендированием.
Alexandroppolus
Да и в структурной типизации TS хватает всякого странного, например вот
nin-jin
Это ожидания у вас странные. Всё нормально тс там вывел.
olivera507224
Прости, а что странного в приведённом тобой примере?
Alexandroppolus
Ну, например, что в виде параметра может закатиться объект с полем
y
, которое неnumber
, а TS уверен, что проверки на наличие поля достаточно. Результат можно увидеть, нажав кнопку Run.olivera507224
Да, согласен с тобой. Действительно неожиданное поведение. Для меня странно что
in
в таком контексте почему-то работает как typeguard, хотя я этого не ожидаю. Как и ты, при написании такого я был бы уверен, что после проверки на наличие ключа TS должен бы вывестиA & { y: unknown }
.bromzh
В этом месте не будет выведения типа, а только сужение из уже имеющегося множества. Изначально у нас тип
param
равенA | B
, так что в дальнейшем он не может вывести в другой типolivera507224
A & { y: unknown }
это тип, который расширяетА
. Вполне логично, что я могу передать его в функцию, и до передачи в функцию TS это учитывает. А вот внутри функции уже забывает от этом. Проблема в том, что TS здесь считает что все, что имеет х и у - это B, но это не так, потому что у у B ограничен конкретным типом number.bromzh
Там нежданчик не в месте проверки и вывода типа
param
, а в месте вызова функции. Странно то, что можно в функцию передатьobj
, потому что он не соответствует типуA | B
, который принимает функция. Тип у obj выводится компилятором как{ x: number, y: null }
, но функция принимает либо{ x: number }
, либо{ x: number, y: number }
. Там на местеy
может быть любой тип, и функция всё-равно его схавает. А ты вроде как ждёшь только A или B, в которомy
будетnumber
.olivera507224
Да, это я проверил уже не с телефона, действительно поведение не очевидное. То, что функция принимает всё, что расширяет
A
- это логично, так и должно быть. С толку сбивает другое - проверка на'y' in param
сужает тип сA | B
доB
, хотя должно бы сужать доA & { y: unknown }
.Alexandroppolus
Передаваемый объект соответствует типу
А
по правилам TS, значит соответствует и типуA | B
В моем примере
A | B
вообще должно схлопнуться доA
, потому чтоB
- подтипA
. Но даже если и не был подтипом, всё равно проверка недостаточна.olivera507224
Для того чтобы избежать такой ситуации, стоит использовать tyguards. Вот так отработает правильно:
Опять же, для того чтобы не опростоволоситься - нужно заранее знать, что TS в приведённом тобой примере будет вести себя таким образом.
Либо, как вариант, проверить можно вот так:
Но я с тобой согласен и в твоём примере такого поведения TS не ожидал.
KataevAS
На самом деле тут нет ничего странного, результат пересечения типов
B | A = { x: number, y?: number }
, именно поэтомуy
- может иметь значение null от этого и необходимо отталкиваться в порядке проверок внутри функции ПРИМЕРKataevAS
Во избежание критики, поправлюсь не пересечения, а объединения типов, описался. Чтобы получить ожидаемый результат, приведу еще один пример
Alexandroppolus
Но только если
B | A
заменить на{ x: number, y?: number }
, то совсем всё по-другому, проверки делаются корректно.Ваш второй пример тоже не сообщает об ошибке типов, если немного поменять obj
KataevAS
Вы правы, но это буквальное понимание, реальное я не могу имитировать средствами js, тут больше подойдут картинки из объяснения механики работы объединения.
По поводу изменений второго примера, больше походит на попытку "обмануть систему", типизация в TS имеет некую "синтетику", в которой правила игры Вы описываете на этапе типизации исходных данных, т.е. если вы не описали, что полученный данные могу иметь null, то TS и не будет об этом знать, это Ваш контракт с собственной типизацией проекта. Реальность же будет выглядеть так, что если вы подготавливаете исходные данные, то и гарантировать их соответствие придется самостоятельно, например, просить TS явно их валидировать.
Alexandroppolus
В этом последнем примере - частный случай: объектный литерал, создаваемый вручную "на лету". Он дополнительно проверяется на отсутствие посторонних полей в объекте. А для всего остального - только проверка указанных полей.
GospodinKolhoznik
Вот так вроде всё хорошо, т.е. компилятор ругается:
Однако если сделать так, то компилятор не видит проблемы:
Alexandroppolus
{}
- это не "пустой объект", а "что угодно, кроме null и undefined". В переменную х можно воткнуть любое значение, кроме этих двух.GospodinKolhoznik
Тогда я признаю, что неправ. По-видимому я действительно неправильно использую интерфейсы (и не только интерфейсы) typescript.
olivera507224
{fromJust: "WTF? String is not a number!"}
расширяет{}
- любой объект, поэтому компилятор считает, что этоNothing
, а неJust<Number>
. По сути, типMaybe<A>
определён как какой угодно объект или{fromJust: A}
. Потому эта запись валидна.meonsou
Вы не поверите ... https://github.com/nikhilk/scriptsharp
Это буквально то, с чего начинался TS. Ребята компилировали C# в JS, затем обратились к Хейлсбергу и начали делать новый ЯП. Ранний TypeScript пытался быть "SharpScript", поэтому в нём есть интерфейсы, перечисления и прочие фичи, которые в современном его виде только мешают и создают путаницу.