• TypeScript: как убрать null из свойства объекта?

    Aetae
    @Aetae Куратор тега TypeScript
    Тлен
    if (error.value?.statusCode !== 404) не гарантирует, что в user не будет null, мало ли там ошибка 50х или даже нет ошибки, а просто сервер глюканул.

    Так что у тебя два варианта:
    1. То что от тебя хочет typescript, явная проверка:
    if (!user) {
      throw new Error('empty responce')
    }

    2. Исправление типа, если ты очень доверяешь своему серверу:
    а) Вариант предложенный Lynn «Кофеман» с явным кастом;
    б) Обёртка над useFetch которая внутри себя скастует тип по новому или изменение самого типа useFetch.
    Ответ написан
    Комментировать
  • Как хранить и востанавливать стор pinia в роутере?

    Aetae
    @Aetae Куратор тега Vue.js
    Тлен
    Ну, грустно, что ты не использовал нормальный роутер изначально, а прилил свой костыль. Теперь у тебя два пути: переписать всё с использованием роутера или вкорячить ещё один костыль.
    Первое сложнее сейчас, но в дальнейшем куда проще в развитии.
    Второе быстрее сейчас, но чревато полной невозможностью поддержки в будущем.

    В первом случае понятно что делать, во втором - написать что-то с использованием history api. Что-то сложное и замороченное, учитывающее конкретно твоё приложение, с применением pushState и реакцией на popstate.
    Ответ написан
    Комментировать
  • Почему глючат картинки в мобильном браузере?

    Aetae
    @Aetae
    Тлен
    Есть подозрение, что вот это вот создаёт вечный цикл:
    картинка.src = e.target.result
    
    картинка.onloadend = function()
    {
      var width = картинка.naturalWidth 
      var height = картинка.naturalHeight
      var соотношение = width/height
    
      картинка.src = создать_картинку(картинка, 1000, 1000/соотношение)
    }

    1. ставишь картинка.src
    2. картинка загружается
    3. срабатывает картинка.onloadend
    4. ставишь картинка.src
    5. картинка загружается
    6. срабатывает картинка.onloadend
    и т.д.
    Ответ написан
  • Можно ли в Nuxt не рендерить сайт на каждом хите?

    Aetae
    @Aetae
    Тлен
    На всякий, чтоб убедиться что мы на одной волне: обычный SSR работает ровно один раз - когда пользователь только зашёл на сайт. Дальше пользователь перемещается внутри SPA. Каждый раз перезапрашивают SSR страницы только боты.
    По этому обычно тут ничего не оптимизируют.

    Однако если хочется - вместо того, чтоб что-то городить, следует воспользоваться классическим кэшированием: выделить nginx который будет кэшировать ответы, а не мучать сервер, и не париться.
    Ответ написан
    1 комментарий
  • Как узнать, что находится внутри slot?

    Aetae
    @Aetae Куратор тега Vue.js
    Тлен
    Тебе ответили в общем, но в конкретном случае можно просто делать provide и inject в этом дровере. Если есть inject - значит где-то в родителях есть другой дровер и собсно через заинжекченое можно им управлять..
    Ответ написан
    Комментировать
  • Как добавлять в div per-message элементы, но удалять per-string?

    Aetae
    @Aetae Куратор тега JavaScript
    Тлен
    Если шрифт моноширный то какие проблемы то? Высоту ты знаешь ширину ты знаешь. Высоту и ширину символа - тоже знаешь. Соответственно знаешь сколько символов поместится в строке. Берёшь количество символов да считаешь...
    Ответ написан
    Комментировать
  • Как типизировать вложенного объекта в объекте в одну строку?

    Aetae
    @Aetae Куратор тега TypeScript
    Тлен
    Тупо скастовать можно так:
    const result = (blogPosts as Posts)[props.name]

    Но это не правильно, по хорошему ты должен изначально убедиться, что blogPosts - нужного типа:
    // тайпргард: тут проверка что posts действительно Posts; 
    const isPosts = (posts: unknown): posts is Posts => !!posts 
      && typeof posts === 'object' 
    //&& ... ;
    
    if (!isPosts(blogPosts)) throw new Error('wrong blogPosts');
    
    const result = blogPosts[props.name];
    Ответ написан
    4 комментария
  • Как правильно ограничивать передаваемые аргументы классов в TypeScript?

    Aetae
    @Aetae Куратор тега TypeScript
    Тлен
    1. TypeScript работает на этапе компиляции. В рантайме нет никакого тайпскрипта, соответственно и не может быть никаких проверок с ним связанных.
    // Есть библиотеки для подобного, но они сильно жирные и слегка "хакнутые", в простых случаях лучше уж руками

    2. TypeScript имеет структурную типизацию. Что значит, что учитвает он только структуру. Тип получаемый из пустого абстрактного класса будет принимать в себя абсолютно любой объект. Тип из класса с одним полем "id" примет в себя любой инстанс любого класса с полем "id".
    class A { id!: string }
    class B { id!: string }
    class C { 
     id!: string; 
     value!: number; 
    }
    
    const foo: A = new B(); // ok
    const bar: A = new C(); // still ok

    3. Неизвестный тип в TypeScript обозначается unknown. Функции проверки что неизвестный тип является конкретным называются тайпгарды:
    function isString(arg: unknown): arg is string {
      return typeof arg === 'syting'
    }

    Применяя тайпгарды вы полностью берёте на себя ответственность, что поверки истинны.
    Ответ написан
  • Почему у пересечения функций такой ReturnType?

    Aetae
    @Aetae Куратор тега TypeScript
    Тлен
    Ни в чём. Просто ограничение языка. Видимо слишком сложно было сделать и\или обосновать. Возможно в какой-то следующей версии языка пофиксят.

    Вот issue помеченная как "Design Limitation", там есть workaroud(который не стоит юзать в проде, разве что если очень хочется).
    Ответ написан
    5 комментариев
  • Как скрыть элемент страницы с помощью tampermonkey (userscript) в iframe, содержимое которого сделано через react?

    Aetae
    @Aetae Куратор тега JavaScript
    Тлен
    Проще всего это делается через css селектор атрибутов вида [class^="chat__root__"] . Заметьте я использовал не полное имя класса, а только начало и модификатор ^= указывающий сверять только начало(если класс не первый, то можно использовать *=). Почему? Потому что "непонятные буковки" в конце - это генерируемый при сборке хэш, который поменяется при выпуске следующей версии фронта и если вы к нему привяжитесь - ваш скрипт очень скоро перестанет работать.

    Если фрейм с другого адреса, то надо создать этот userscript именно для этого адреса и уже применять там:
    // @run-at document-start
    
    function addCss(css, root = window) {
      const style = root.document.createElement('style');
      style.innerHTML = css;
      (root.document.head || root.document.documentElement).append(style);
      return style;
    } 
    
    const css = `
      [class^="chat__root__"] {
        dislpay: none !important;
      }
    `;
    
    addCss(css);

    Если с этого же, то придётся заморочиться:
    // @run-at document-start
    
    const css = `
      [class^="chat__root__"] {
        dislpay: none !important;
      }
    `;
    
    // отлавливаем загрузку фреймов
    new MutationObserver(() => {
      document.querySelectorAll('iframe:not([us-processed]').forEach((iframe) => {
        if (isAccessibleFrame(iframe)) {
          // добавляем наш css
          addCss(css, iframe.contentWindow);
          
          // на случай если содержимое фрейма перепишут позднее
          iframe.addEventListener('load', () => addCss(css, iframe.contentWindow));
        }
        // помечаем что обработали этот фрем, чтоб не повторять
        iframe.setAttribute('us-processed', true);
      });
    }).observe(document, {childList: true, subtree: true});
    
    // проверяем что содержимое фрейма доступно 
    function isAccessibleFrame(iframe) {
      try {
        iframe.contentWindow.test
        return true
      } catch (e) {
        return false
      }
    }
    Ответ написан
  • Белый айпи через свой сервер?

    Aetae
    @Aetae
    Тлен
    Туннель (любой vpn) до сервера, на сервере nginx, который завернёт запросы к тебе в этот туннель.
    Ответ написан
    Комментировать
  • Как добавить свойство checked по условию входящих данных?

    Aetae
    @Aetae Куратор тега Vue.js
    Тлен
    У тебя проблема не в vue, а в базовом html:
    Оба input у тебя получают одинаковый id и оба label одинаковый for. Поведение браузера при клике на label в таком случае не определено, но на практике это значит, что клик идёт всегда первому input.

    Соответственно надо сделать либо так:
    <label class="form-check-label">
      <input 
        type="checkbox" 
        role="switch"
        v-model="methodId"
        :value="method.id"
        class="form-check-input" 
      />
      {{ method.name_method }}
    </label>

    Либо как-то так:
    <input 
      :id="`input-${method.id}`" 
      type="checkbox" role="switch"
      v-model="methodId"
      :value="method.id"
      class="form-check-input" 
    />
    <label :for="`input-${method.id}`" class="form-check-label">
      {{ method.name_method }}
    </label>
    Ответ написан
    1 комментарий
  • Как заверстать кнопку?

    Aetae
    @Aetae
    Тлен
    Мужик, ты только копировать из фигмы умеешь?
    Поменять местами порядок уже выше твоих возможностей?

    Вот даже жалуются на это поведение фигмы. Но то что это фигма кривая - тебя не оправдывает.
    Ответ написан
  • Можно ли опустить % после 0 в CSS?

    Aetae
    @Aetae
    Тлен
    Не всегда, в некоторых случаях 0% != 0, например для flex-basis. :)
    Ответ написан
    8 комментариев
  • Почему не работает Array.from(value) при переводе formData в массив?

    Aetae
    @Aetae Куратор тега JavaScript
    Тлен
    Ну да, Array.from(File) - пустой массив, потому что у File нет ни length ни числовых индексов, а чего ты хотел?

    FormData хранит множество файлов как множество записей с одинаковым именем, по одному файлу в каждой, а не как одну запись с массивом всех файлов.
    Ответ написан
    Комментировать
  • Как правильно настроить swiper в react?

    Aetae
    @Aetae Куратор тега JavaScript
    Тлен
    Компонент Swiper не ждёт свойства spaceBetween. Вы уверены, что оно хоть что-то делает?

    Если это баг типизации Swiper и на самом деле он такое свойство ждёт, то вам следует репортить этот баг автору компонента (предварительно обновившись до последней версии).

    В крайнем случае можно прибегнуть к declaration merging, но это вредный костыль:
    declare module 'путь до типов компонента Swiper' {
      interface SwiperProps {
        spaceBetween: number;
      }
    }
    Ответ написан
    Комментировать
  • Как скрыть этот текст при наведении?

    Aetae
    @Aetae
    Тлен
    Убрать атрибут title. Или если нужно убрать только для нижестоящего элемента, оному можно прописать title="".
    Ответ написан
  • Как пофиксить баг методов scrollTo и scrollIntoView в chrome?

    Aetae
    @Aetae Куратор тега JavaScript
    Тлен
    Написать в багтреккет хрома.:)

    Такая шляпа наблюдается только при smooth. Можешь пока убрать его для хрома пока не починят. Ну или использовать какую-нить кастомную либу для smooth скола.
    Ответ написан
  • Prettier ставит ненужные скобки, как отключить?

    Aetae
    @Aetae Куратор тега JavaScript
    Тлен
    Прям на главной странице написано: Prettier - An opinionated code formatter.
    Иными словами: не нравится как форматирует prettier - не используй его. Иных вариантов нет.
    Ответ написан
    Комментировать
  • Как отследить область события "click"?

    Aetae
    @Aetae Куратор тега JavaScript
    Тлен
    if(event.target.closest('<селекторы которые надо игнороиовать>'))
      return;
    // закрываем
    Ответ написан
    Комментировать