Ответы пользователя по тегу TypeScript
  • Типизация функции, возвращающей разные объекты?

    Aetae
    @Aetae
    Тлен
    Проще всего сделать так, ts сам подберёт типы:
    const elementDefaults = {
      'welcome': {
        placeholder: 'Type welcome message...',
        question: '',
        isDescription: false,
        description: '',
        startButtonText: 'Start',
      },
      'checkbox': {
        placeholder: 'Type question or statement...',
        question: '',
        isDescription: false,
        description: '',
        options: [] as string[],
        multiple: false,
      }, 
      'dropdown': {
        placeholder: 'Type question here...',
        question: '',
        isDescription: false,
        description: '',
        options: [] as string[],
      },
      'rating': {
        placeholder: 'Type question...',
        question: '',
        isDescription: false,
        description: '',
        steps: 10,
        defaultRate: 0,
        shape: 'stars',
      },
      'text': {
        placeholder: 'Type question...',
        question: '',
        isDescription: false,
        description: '',
        maxLength: 99999,
      }, 
      'slider': {
        placeholder: 'Type question...',
        question: '',
        isDescription: false,
        description: '',
        steps: 10,
      }, 
      'thanks': {
        placeholder: 'Type message...',
        question: '',
        isDescription: false,
        description: '',
      }
    }
    
    
    export function getElementSettings<E extends keyof typeof elementTypes>(type: E) {
      if(!(type in elementDefaults)) throw new Error("element type doesn't match!");
      return elementDefaults[type];
    }

    Но если хочется по правилам, то как-то так:
    type ElementSetting = {
      placeholder: string;
      question: string;
      isDescription: boolean;
      description: string;
    }
    
    type ElementSettings = {
      welcome: ElementSetting & {
        startButtonText: string;
      },
      checkbox: ElementSetting & {
        options: string[];
        multiple: boolean;
      },
      dropdown: ElementSetting & {
        options: string[];
      },
      rating: ElementSetting & {
        steps: number;
        defaultRate: number;
        shape: string;
      },
      text: ElementSetting & {
        maxLength: number;
      },
      slider: ElementSetting & {
        steps: number;
      },
      thanks: ElementSetting
    }
    
    const elementDefaults: ElementSettings = {
      'welcome': {
        placeholder: 'Type welcome message...',
        question: '',
        isDescription: false,
        description: '',
        startButtonText: 'Start',
      },
      'checkbox': {
        placeholder: 'Type question or statement...',
        question: '',
        isDescription: false,
        description: '',
        options: [],
        multiple: false,
      },
      'dropdown': {
        placeholder: 'Type question here...',
        question: '',
        isDescription: false,
        description: '',
        options: [],
      },
      'rating': {
        placeholder: 'Type question...',
        question: '',
        isDescription: false,
        description: '',
        steps: 10,
        defaultRate: 0,
        shape: 'stars',
      },
      'text': {
        placeholder: 'Type question...',
        question: '',
        isDescription: false,
        description: '',
        maxLength: 99999,
      },
      'slider': {
        placeholder: 'Type question...',
        question: '',
        isDescription: false,
        description: '',
        steps: 10,
      },
      'thanks': {
        placeholder: 'Type message...',
        question: '',
        isDescription: false,
        description: '',
      }
    }
    
    
    export function getElementSettings<E extends keyof ElementSettings>(type: E): ElementSettings[E] {
      if(!(type in elementDefaults)) throw new Error("element type doesn't match!");
      return elementDefaults[type];
    }
    Ответ написан
  • Почему скрипт запуска проекта из package.json падает с ошибкой?

    Aetae
    @Aetae
    Тлен
    Винда не считает ' кавычками и кидает их как часть параметра.
    Экранировать чтоб оно работало на всех ОС - не так просто, а результат - уродлив, так что рекомендуется просто указать параметры для перезаписи под ключом ts-node в tsconfig.json:
    {
      "ts-node": {
        "compilerOptions": {
          "module": "CommonJS"
        }
      },
      ...
    }
    Ответ написан
  • Как исправить ошибку Property 'item' does not exist on type 'Record'?

    Aetae
    @Aetae
    Тлен
    Во-первых: как верно заметил YavaDev: classes[item].
    Во-вторых: только вручную, на свой страх и риск:
    for(let item in classes) {
        classes[item as keyof typeof classes] = 'page'+item
    }
    В typescript специально не добавили автоматическую типизацию ключей оставив просто string, так как из-за его структурной природы нельзя наверняка сказать, есть ли в полученном объекте(или его прототипе) ещё какие-то ключи, кроме тех, что указаны в его типе, и, соответственно, нельзя быть уверенным, что ничего не сломается.
    Ответ написан
  • Фильтрация вложенных данных React?

    Aetae
    @Aetae
    Тлен
    1. В любой строке встречается пустая строка, по этому такой поиск выдаёт все значения.
    2. map складывает в выходной массив результат переданной функции. Поскольку она у вас возвращает отфильтрованный массив items, то в итоге у вас получается массив массивов items. Если вам нужно, чтоб возвращались категории - возвращайте категории.

    Ну и дважды одну и ту же работу делать не надо, можно обойтись одним reduce:
    сonst filterData = filter(arr, input.value);
    
    interface Category {
      category: string;
      list: Array<{
        item: string;
      }>;
    }
    
    function filter<T extends Category>(data: T[], value: string): T[] {
      if (!value) return data.slice(); // или [] если при пустом value нужен пустой массив
      value = value.toLowerCase();
      
      return data.reduce((result, category) => {
        if(category.category.toLowerCase().includes(value)) {
          result.push(category);
        } else {
          const list = category.list.filter(({ item }) => item.toLowerCase().includes(value));
          if (list.length) {
            result.push({
              ...category,
              list
            });
          }
        }
        return result;
      }, [] as T[])
    }
    Ответ написан
  • Как можно корректно написать асинхронный метод у объекта в typescript с дженериком?

    Aetae
    @Aetae
    Тлен
    Что именно ты хочешь сократить, вроде ж дальше некуда: один тип на вход - один на выход?

    Ну можешь убрать async и await, они здесь не нужны:
    const ApiServiceModule = {
      get: <T>(url: string): Promise<T> => fetch(url)
        .then(response => response.json())
        .catch(err => console.error(err))
    }
    async/await всего лишь сахар над Promise и в данном случае ничего не делают, т.к fetch и так возвращает Promise.

    P.S. Ну и методом я бы это не назвал, это свойство с функцией. Метод имеет доступ к this.
    Ответ написан
  • Реален ли такой дженерик в TypeScript?

    Aetae
    @Aetae
    Тлен
    Вот так с указанием на аргументы:
    function wrapper<T extends { start(...args: unknown[]): unknown }>(target: { new(): T }, ...args: Parameters<T['start']>): T {
      let instance = new target();
      instance.start(...args);
      return instance;
    }
    
    
    class RandomClass {
      start(arg1: string, arg2: number) { /* ... */ }
    }
    let instance = wrapper(RandomClass, 'Hello, world!', 777); /// все ок
    let instance2 = wrapper(RandomClass, 777); /// ошибка
    Ответ написан
  • TSlinter ругается на символ?

    Aetae
    @Aetae
    Тлен
    Если не знаете английского языка - выкиньте линтер. Какая вам польза от того, что он вам пишет "какие-то" сообщения, которые вы не способны прочитать?
    Ответ написан
  • Как типизировать массив ключей интерфейса?

    Aetae
    @Aetae
    Тлен
    Тут есть несколько решений.
    Например:
    type TupleUnion<U extends string, R extends string[] = []> = {
    	[S in U]: Exclude<U, S> extends never ? [...R, S] : TupleUnion<Exclude<U, S>, [...R, S]>;
    }[U] & string[];
    
    interface Interface {
      foo: boolean;
      bar: string;
      baz: object
    }
    
    type Keys = TupleUnion<keyof Interface>; 
    
    let keys: Keys;
    
    keys = ['foo', 'bar', 'baz']; // OK все ключи указаны
    keys = ['foo']; // NOT OK указаны не все ключи
    keys = ['foo', 'bar', 'another bar']; // NOT OK один из ключей не совпадает

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

    Aetae
    @Aetae
    Тлен
    Очевидно нужен отдельный пакет, в котором будет общее для всех сервисов.
    Ответ написан
  • В чем разница между type и enum?

    Aetae
    @Aetae
    Тлен
    Тем что Weekday2s.mon === 0. Если нужны в enum именно строки - то именно строки и следует задавать: enum Weekdays { mon = "mon", ...}
    В остальном, этого:
    Ну кроме того что enum скомпилируется в JS - объект, а type будет доступен только во времени компиляции.

    более чем достаточно. Вместо того чтобы работать со строками(каждый раз новыми), ты работаешь объектом.
    Ответ написан
  • Есть ли что-то типа транскомпилятора(для браузера) для typescript?

    Aetae
    @Aetae
    Тлен
    Если дёшево и сердито: tsc --watch, но адекватный вариант - юзать системы с live reload'ом, например одну из предложенных Алексей Ярков.
    Подключать надо всё равно js, компилировать на лету в браузере - безумие и бессмыслица, т.к. ты не сможешь следить за изменениями и должен будешь каждый раз в ручную перегружать страницу и каждый раз перекомпилировать весь код целиком, а не дельту как при нормальном способе.
    Ответ написан
  • Как правильно написать рекурсию?

    Aetae
    @Aetae
    Тлен
    Используй готовые либы(или смотри на их код).
    Сейчас миксины в ts представляют собой костыли поверх багов.

    По твоему примеру: ты не можешь просто взять массив и получить из него вразумительные типы. Тебе нужны оврлоады на каждый отдельный тип, чтоб получить на выходе юнион.
    Я мог бы что-нибудь накостылить, но не буду, потому что это больно.)
    Ответ написан
  • Что стоит использовать type или интерфейс?

    Aetae
    @Aetae
    Тлен
    Мысли простые на самом деле: зри в корень.
    Интерфейсы используй для описания интерфейсов, типы используй для описания типов.
    И нет, это не одно и тоже.
    Если утрировать: интерфейс - это описание структуры данных, встречающееся на стыке взаимодействия компонентов системы или разных систем, в основном используется только на этом самом стыке; тип - это внутренние сущности которыми оперирует система и которые встречаются повсеместно.
    Ответ написан
  • Каким способом вы определяете тип функции в вашем приложении?

    Aetae
    @Aetae
    Тлен
    Ну IDE тебе подскажет при вводе.)
    А что вводить - ты должен знать и так: ты же знаешь с чем функция твоя работает.) Если потенциально по логике твоя функция должна работать с чем-то ещё, но ты об этом не знал на момент написания, то значит ты не предусмотрел этого и внутри функции тоже, а значит отсутствие указанного типа только в плюс.
    Поизучать типы можно полазив по .d.ts соответствующих либ. IDE и тут поможет: ctrl+тык на имеющуюся функцию откроет её декларацию.

    В целом же в TS структурная типизация, тебе не надо знать с какими именами типов работает пользователь, тебе надо лишь указать структуру нужного типа.
    Ответ написан
  • Какой тип указать для children.current у TS?

    Aetae
    @Aetae
    Тлен
    Возможно ак:
    const {current}: {current: HTMLUListElement} = children;

    или так:
    const current = children.current as HTMLUListElement;

    Вы же задаёте тип не current, а всего объекта.

    P.S. Про ts-ignore забудьте.
    Ответ написан
  • Google Recaptcha Type?

    Aetae
    @Aetae
    Тлен
    И, какие проблемы?
    Идёшь сюда и смотришь есть ли то, что тебе надо. Если нет - то скорее всего нигде нет и надо писать самому, но можно погуглить: иногда некие персонажи с "уникальной личностью" не делятся типами в общий репозиторий.
    В твоём случае, впрочем, всё есть: @types/recaptcha2 и @types/grecaptcha.
    Ответ написан
  • Почему ругается TypeScript?

    Aetae
    @Aetae
    Тлен
    Typescript работает только с кодом, он не знает что-там в Vue шаблоне, увы. Потому в $refs у него лежат голые компоненты Vue или Element'ы.
    Я лично вручную указываю через объединение интерфейсов - внизу добавляю перекрывающий:
    @Component
    export default class Login extends Vue { 
      // ...
    }
    export default interface Login {
      $refs: {
         loginForm: any; // на самом деле не any, а интерфейс компонента, поддерживающий нужные методы
      }
    }
    Ответ написан
  • Как подключить ESLint к проекту?

    Aetae
    @Aetae
    Тлен
    Должно быть очевидно из сообщения об ошибке, нет? Выше в корне проекта у вас лежит ещё один файл .eslintrc, который как-то конфликтует с вашим.
    Ответ написан
  • Как можно улучшить участок код?

    Aetae
    @Aetae
    Тлен
    filterUrlBuilders.filter((filter) => filter.url).map((filter) => filter.url);

    Это обычно делается так:
    filterUrlBuilders.map(filter => filter.url).filter(Boolean);

    В целом же весь вопрос в классах FilterUrlCombiner и FilterUrlBuilder: они действительно нужны и выполняют какую-то полезную работу или у кого-то энтерпрайз головного мозга?
    Ответ написан