Architec.Ton is a ecosystem on the TON chain with non-custodial wallet, swap, apps catalog and launchpad.
Main app: @architec_ton_bot
Our Chat: @architec_ton
EU Channel: @architecton_eu
Twitter: x.com/architec_ton
Support: @architecton_support
Last updated 1 month ago
Канал для поиска исполнителей для разных задач и организации мини конкурсов
Last updated 1 month, 3 weeks ago
Что с ресурсами?
Попробую в заметке выяснить, что это и коротко подчеркнуть плюсы/минусы, которые вижу я.
Ресурс состоит из функции loader(), возвращающей Promise
и опционального сигнала. Функция срабатывает при инициализации ресурса и при изменении параметров сигнала.
cities = resource({
request: () => ({ id: this.id() }),
loader: (param) => {
return this.service.findCity(param.request);
}
});
Новое API:
📌 обладает семантикой switchMap. Другими словами, предыдущие запросы будут отклонены и возвращены последние запрашиваемые данные.
📌 позволяет удобно обрабатывать ошибки и состояние загрузки. Можно просто обратиться к ресурсу и получить состояние.
this.cities.isLoading;
this.cities.error;
📌 присутствует совместимость с RxJS.
Преимущества
1. Позволяет легко управлять состоянием загрузки, успешного завершения и ошибок без необходимости писать собственные велосипеды.
2. Возможная интеграция с Angular Forms. Это было бы круто связать данные между формами и асинхронными источниками. Есть в сети примеры с linkedSignal и формами.
3. Кэширование данных, что может значительно повысить производительность приложения, уменьшая количество запросов к серверу.
// EditUserComponent
userId = input<string>();
userRes = rxResource({
request: () => ({ id: this.userId() }),
loader: (param) => this.service.getUser(param.id);
})
form = {
name: linkedSignal(() => this.userRes.value().name),
email: linkedSignal(() => this.userRes.value().email)
};
Недостатки
📌 Снова получаем 1000 и 1 способ сделать одно и то же.
Противоречие существующему HttpClient
. Очень интересно, представят ли в следующих версиях отдельный HttpClient
с тем же API, но возвращающим Promise
?
📌 Будет ли такая гибкость, как у RxJS? Пока что есть ощущение, что придется преобразовывать туда/обратно, что приведет к невообразимому количеству бойлерплейта. Если хотели уменьшить порог входа, то получили пока ровно обратное.
Пример, как на фото в комментариях, лично для меня сложно читаем. Это то, что ждут от Angular сейчас? Чтобы не тратить часы на разбор, цель в примере: получить список городов по запрашиваемому году основания.
Команда Angular (совместно с авторами Angular Space community) обновят весьма устаревший style guide!
На прошлой неделе RFC (Request For Comments) был опубликован, просмотреть у меня получилось только на выходных.
Я предполагал, что в гайде покажут стиль работы с новыми API, интеграции с RxJS, работу с конвертацией toSignal()
/ toObservable()
и тд. Но для этого придется ждать последующих обновлений.
Из интересного:
📌 Автор в комментах предлагает помечать свойства класса, которые используются только в шаблонах, как protected
и уже сейчас переписать тесты, опираясь на это правило.
📌 Добавление типа сущности в имена (component, service, pipe) - от данного подхода RFC предлагает отказаться, что вызвало бурное обсуждение. На мой взгляд, подобное правило приведет к путанице. Данный подход не должен быть регламентирован в официальном style guide, а принят в конкретном проекте командой/техлидом и изменен, если считаете, что это лучше отразит функциональность.
📌 Рекомендация писать отдельный файл для шаблона, если размер превышает несколько строк - будет убрана. И здесь, конечно же, отсылка к распространению JSX. О DevExp команда предпочла здесь забыть…
Что же, ждем. После столь значительных нововведений разработчики должны знать, на что ссылаться, применять на проектах. Ссылка на RFC здесь для вас.
Типизация или опять костылизация?
На прошлой неделе открыл для себя один немаловажный нюанс.
В своем решении мне нужно было передавать в аргумент функции KeyboardEvent
. При включенном strict mode и попытке считать значение event.target.value
, как в примере ниже, получаем ошибку: TS2339: Property value does not exist on type EventTarget
.
```
private keydownHandler(event: KeyboardEvent): void {
if (
event.target &&
event.target.value
) {
...
}
}
```
Первое решение, которое пришло в голову, было сделать принудительный каст. Это решало проблему, но так делать плохо. Гораздо удобнее и правильнее было бы использовать type guard.
```
private keydownHandler(event: KeyboardEvent): void {
if (event.target instanceof HTMLInputElement && event.target.value) {
...
}
}
```
Но, насколько я знаю, HTMLInputElement
это интерфейс, соответственно это не сработает. Оказывается, сработает! Дело в том, что если посмотреть в lib.dom.d.ts
, то можно найти, что HTMLInputElement
это и интерфейс, и объявление класса:
```
interface HTMLInputElement extends HTMLElement, PopoverInvokerElement {...}
declare var HTMLInputElement: {
prototype: HTMLInputElement;
new(): HTMLInputElement;
}
```
Поэтому решение с instanceof
сработает. Но похоже, что сделано специально для подобной проверки, но подход весьма сомнительный. А вы знали об этом? И как вы относитесь к подобному решению?
Web-view, In-app браузеры и недостатки in-app
В чем отличия?
? Web-view — это компонент, интегрированный в приложение, который позволяет отображать веб-страницы. Он использует движки браузеров (WebKit на iOS или Chromium на Android). Навигация может быть ограничена. Например, кнопки вперед/назад могут функционировать по-другому. Кроме того, web-view более уязвим к определенным видам атак, поскольку он может не иметь всех функций безопасности, которые предоставляет полноценный браузер.
? In-app браузер — это обёртка над WebView, которая имеет полный контроль над вашей страницей. Они запускаются из приложения, но работают как полноценные браузеры. Они обычно реализуются через такие компоненты, как Chrome Custom Tabs (на Android) или SFSafariViewController (на iOS). Предоставляют почти все функции полноценного браузера, включая вкладки, расширения и улучшенные функции безопасности. Имеют более высокие меры безопасности, включая защиту от фишинга и автоматические обновления.
На frontend-masters недавно вышла статья, объясняющая, почему такие In-app браузеры зло, и как с ними бороться.
В итоге, выбор между web-view и in-app браузером зависит от целей разработчика и требований к пользовательскому опыту. Web-view может быть удобным для легкой интеграции, но in-app браузеры обеспечивают более привычный функционал и безопасность.
Миграция на function-based inputs станет удобнее!
В следующей версии Angular появится schematic для миграции decorator-based инпутов на inject function.
Миграция будет выполняться с использованием команды ng generate @angular/core:inject\-migration
с несколькими возможными опциями:
- path. Указывается путь миграции. Если оставить пустым, мигрирует всю директорию.
- migrateAbstractClasses. Указывается, если нужно мигрировать абстрактные классы, но есть вероятность, что придется вручную исправлять.
- backwardsCompatibleConstructors. При миграции будет сгенерирована дополнительная сигнатура конструктора для обратной совместимости.
Новый схематик появится в версии 18.2.0 и упростит переход. Ссылка на MR.
GitHub
Initial logic for signal input migration by devversion · Pull Request #57082 · angular/angular
This commit adds the code for the signal input migration. We've prototyped the migration and made it batchable— so that it can run for larger projects (e.g. using Beam); or in practice all of G...
Отличие Omit и Exclude
При необходимости исключить свойство или набор свойств из типа, мы вспоминаем, что есть Utility types - Omit и Exclude. Но для того чтобы понять, какой применить, зависаешь на несколько секунд. Особенно, если редко с ними работаешь.
Возьмем простейший пример и выкинем ненужные свойства из объекта.
```
interface ITodo {
title: string;
description: string;
completed: boolean;
createdAt: number;
}
type TodoInfo = Omit;
const todoInfo: TodoInfo = {
title: "Title",
description: "Smth description",
};
```
Мы убрали свойства из типа ITodo
. Теперь попробуем сделать то же самое с объединением интерфейсов.
interface ITodo {
title: string;
description: string;
completed: boolean;
createdAt: number;
}
interface IWork {
id: string;
executor: string;
}
type TodoInfo = Omit<ITodo | IWork, "completed" | "createdAt" | "id">;
// type TodoInfo = {}
В этом случае, Omit
уже выведет неправильный тип. Переформулируем наши требования. Для такой задачи нужно, чтобы наш условный тип игнорировал ключи, которые содержатся в исходном типе ITodo | IWork. Верно?
Если обратим внимание на определение типов, то увидим, что Exclude
делает то, что нужно.
type Exclude<T, U> = T extends U ? never : T;
Он просто проверяет, расширяет ли один тип другой. Если да, то возвращается never
, иначе возвращается исходный тип. Exclude
, по сути, использует дистрибутивное свойство Conditional types.
Заменим Omit
на Exclude
в нашем примере. В этом случае TodoInfo
все равно выводится криво, но это уже недостатки автовывода типов в TS. В ошибке компилятор выводит требуемые свойства и после их добавления код будет рабочим.
```
// type TodoInfo = ITodo | IWork
type TodoInfo = Exclude;
// Type '{ title: string; description: string; }' is missing the following properties from type 'ITodo': completed, createdAt
const todoInfo: TodoInfo = {
title: "Title",
description: "Smth description",
};
const todoInfo: TodoInfo = {
title: "Title",
description: "Smth description",
completed: false,
createdAt: 1,
};
```
Сделаем вывод.
Omit работает с объектами или интерфейсами, чтобы убрать одну из пар “key-value”
Exclude работает с объединениями (unions), чтобы исключить одно из свойств.
Architec.Ton is a ecosystem on the TON chain with non-custodial wallet, swap, apps catalog and launchpad.
Main app: @architec_ton_bot
Our Chat: @architec_ton
EU Channel: @architecton_eu
Twitter: x.com/architec_ton
Support: @architecton_support
Last updated 1 month ago
Канал для поиска исполнителей для разных задач и организации мини конкурсов
Last updated 1 month, 3 weeks ago