Ответы пользователя по тегу TypeScript
  • Как передать любой тип используя дженерики?

    search
    @search
    мама говорит что я особенный
    TBody в таком случае должен стать дженериком.

    type TUserInfo = {
       id: num,
       readonly fname: string,
       readonly lname: string
    }
    
    type TBody<T> = {
       success: boolean,
       user?: T
    }


    И далее по ходу

    const fechUserInfo = (): Promise<TBody<TUserInfo>> => {
      return fetch().then(response => response.json()).then((user: TUserInfo) => ({success: true, user}));
    }
    Ответ написан
    Комментировать
  • Что делать если нет @types для react пакета?

    search
    @search
    мама говорит что я особенный
    В таком случае вам понадобится создать *.d.ts файл самостоятельно и подключить его в tsconfig.json

    Вот тут подробнее https://www.typescriptlang.org/docs/handbook/2/typ...
    Ответ написан
    1 комментарий
  • Как правильно определять тип объекта в Typescript (React)?

    search
    @search
    мама говорит что я особенный
    Тайпскрипт правильно ругается потому что таргет события не обязательно должен быть дом элементом. События могут так же порождаться, например XHR запросами.

    Я бы на вашем месте сделал так называемую type guard функцию, в которой убеждался бы что таргет действительно элемент дом. Все элементы дом наследуются от объекта HTMLElement. Это можно использовать для проверки:

    const isHtmlElement = (v: any): v is HTMLElement => v instanceof HTMLElement;


    далее мы можем использовать эту функцию для проверки нашего таргета:

    const eventHandler = (e: Event) => {
      if (!isHtmlElement(e.target)) {
        return;
      }
      // Вот здесь мы можем смело работать с таргетом как с ДОМ Элементом
      e.target.classList.toggle('active');
    }


    УПД

    Еще информация к размышлению.

    Финальный код, сгенерированный тайпскриптом, не содержит информации о типах. В рантайме нельзя узнать тип интерфейса, выполнив, например `peremennaya instanceof VashInterfeis`. Но всегда можно создать type guard функию, которая будет определять что объект именно нужного типа по каким-то косвенным признакам (например по наличию определённых полей в объекте). Так как код guard функции невозможно провертить статическим анализватором, тайпскрипт не может гарантировать того что ваша guard фунция верна и не пропускает всё подряд. Поэтому, хорошим тоном является писать такой код, который не нуждается в подобных проверках. Это возможно. Код при таком подходе становится стройнее и легче для осмысления.
    Ответ написан
    1 комментарий
  • Что использовать Сервисы или Глобальные хранилища?

    search
    @search
    мама говорит что я особенный
    Переменные в сервисах мало чем отличаются от глобальных переменных. По сути - это и есть глобальные переменные со всеми вытекающими последствиями. Например, переменная сервиса может быть неожиданно изменена во время какого-нибудь асинхронного действия. Что приведёт к неожиданным/нежелательным сайд-эффектам. Современные ООП парадигмы (например, ДДД), напрямую говорят о том что сервисы не должны хранить состояние.
    Ответ написан
    Комментировать
  • Как развернуть юнион в интерфейс?

    search
    @search
    мама говорит что я особенный
    Вы, наверное это имели ввиду:

    type union = 'a' | 'b' | 'c'
    type I = {
      someOtherField?: number;
    } & Record<union, any>;
    // result:
    interface I {
      someOtherField?: number;
      a: any
      b: any
      c: any
    }


    Если вам не нужны дополнительные поля в интерфейсе (типа someOtherField из примера), то можно обойтись просто Record<union, string>. Как-то так:

    type I = Record<union, any>;
    Ответ написан
    3 комментария
  • Как заполнить state?

    search
    @search
    мама говорит что я особенный
    Не совсем понял проблему, но стены находятся в первом элементе массива action. Если вы хотите передать их в state, то это можно сделать как-то так

    game$.subscribe((action) => {
      switch (action[0]) {
        case 'ArrowUp':
          if(state.y > 0) { state.y--; }
          break;
        case 'ArrowRight':
          if(state.x < gameWidth - 1) { state.x++; }
          break;
        case 'ArrowDown':
          if(state.y < gameHeight - 1) { state.y++; }
          break;
        case 'ArrowLeft':
          if(state.x > 0) { state.x--; }
          break;    
      }
      
      state.walls = action[1];  
      renderGame(state);
      console.log(state)
    });
    Ответ написан
    Комментировать
  • Как связать компоненты между страницами?

    search
    @search
    мама говорит что я особенный
    Вынесите объявление сервиса в `providers` главного модуля. И уберите объявление сервиса из `providers` других модулей.

    Каждый раз когда вы добавляете сервис в `providers` модуля, анугяр создаёт экземпляр сервиса именно для этого модуля. И в другом модуле этот экземпляр виден не будет.
    Ответ написан
    Комментировать
  • Angular - Не работают стандартные значения переменой?

    search
    @search
    мама говорит что я особенный
    Только ручками, тайпскрипт за вас это чинить не будет.

    // Класс здесь не нужен. Старайтесь предпочитать интерфейсы классам если у объекта нет методов
    export interface NameSurName {
      name: string;
      surname: string;
    }
    
    ...
    
    this.nameSurName = {
      name: '',
      surename: 'Иванов',
      ...resp.data
    }


    На вопрос "почему так" ответ: тайпскрит не добавляет в код никакой магии. Конечный код скомпилированный из тайпскрипта выглядет в JS почти так же как и с тайпскриптом, только без типов. Короче, TS не занимается преобразованием типов за вас.

    Вот есть официальный playground от создателей. Можно ради интереса иногда попроверять что получится из вашего TS кода.
    Ответ написан
    Комментировать
  • Rxjs - как сделать двойной subscribe?

    search
    @search
    мама говорит что я особенный
    Обзёрвер не выполняет никакой работы до тех пор пока не была вызвана функция subscribe. Сам процесс вызова subscribe называется "подписка". Как только функция subscribe была вызвана (т.е. на обзёрвер подписались) - дело пошло и обзёрвер начал свою работу. До тех пор пока subscribe не вызван, обзёрвер - это просто рецепт того что нужно делать когда прийдут данные.

    Сама функция subscribe возвращает деструктор. Деструктор - это что-то что нужно выполнить, если вдруг понадобилось остановить обсёрвер (например прервать HttpConnection).

    Код ниже возвращает функцию-деструктор

    let get = () => {
        return this.http.get(url)
            .subscribe((response: ResponseObject) => {...});
    }


    На функцию-деструктор невозможно подписаться. Коллбеков у неё тоже нет. Её можно только выполнить для того чтоб остановить обзёрвер.

    Поэтому, универсальный рецепт - это никогда не подписываться в самих сервисах. Если вам нужно что-то проделать с данными из обзёрвера в самом сервисе, то можно воcпользоваться оператором tap:

    let get = () => {
        return this.http.get(url)
            .pipe(
              tap((response: ResponseObject) => {...})
            );
    }
    
    // а дальше где-то в коде сделать
    
    service.get().subscribe((response: ResponseObject) => {...})


    Более того, вы можете делать tap (и любой друго pipe оператор) пока у вас есть обзёрвбл:

    service.get()
      .pipe(
        tap(...),
        map(...),
        whatever(...),
      ).subscribe((response: ResponseObject) => {...})


    Вам будет проще понять механизм работы обзёрвблов, если вы будите рассматривать обзёрвбл как функцию, а метод subscribe как способ выполнить эту функцию.

    Учитывая вышесказанное:

    const observable = service.get();
    observable.subscribe((result) => {...}); //выполнит запрос к серверу
    observable.subscribe((result) => {...}); //выполнит запрос к серверу еще раз
    // запрос к серверу будет инициироваться каждый раз когда будет выполняться функция subscribe
    Ответ написан
    2 комментария
  • Как в RxJS сделать переодичный вызов в n времени, только после завершения текущей итерации?

    search
    @search
    мама говорит что я особенный
    Как-то так:

    this.httpClient.request(...).pipe(
      repeatWhen(complete => complete.pipe(delay(20000))
    ).subscribe(result => console.log(result))
    Ответ написан
    Комментировать
  • Property 'title' does not exist on type, Argument of type?

    search
    @search
    мама говорит что я особенный
    Потому что this.request(id) возвращает или faceProductList[][] или faceProductList[].

    А array.filter(({title}) => title.includes(valueSearch)) однозначно обрабатывает данные как faceProductList[] и не учитывает faceProductList[][].

    Можно сделать

    public async handler(id: string, valueSearch: string) { 
            await this.request(id)
              .then((array: faceProductList[]) => { 
                ...

    для того чтоб ошибка ушла.

    Но проблема неоднозначности останется и однажды вылезет в виде бага.

    На вашем месте я бы сделал как-то так:

    public async request(id: string): Promise<faceProductList[][]> {
      const res = await fetch(`${this.url}${id}`);
      const resArr: faceProductList[] | faceProductList[][]  = await res.json();
      if (resArr.length === 0) {
        return resArr;
      }
    
      if (Array.isArray(resArr[0])) {
        return resArr;
      }
    
      return [resArr];
    }


    не могу гарантировать что это заработает сразу, возможно прийдётся подпилить. Но направление мысли должно быть понятным.

    Плюс этого подхода - вы будете избавлены от проверки на "а что именно вернула request, faceProductList[] или faceProductList[][] ?" при каждом чихе.
    Ответ написан
    1 комментарий
  • Typescript/Angular: что не так с возвратом результата асинхронной функции?

    search
    @search
    мама говорит что я особенный
    Вроде, если сделать
    axios.get<Room[]>('somepath/kek:1488?SeigHeil&joking=true')...

    , то тайпскрипт перестанет выпендриваться. Потому что будет явно указано какой тип данных возвращается сервером.

    UPD: еще такой момент, ожидается что сервак возвращает массив Rooms, так что rooms.push(response.data); не заработает как ожидалось потому что в итоге получится что переменная rooms будет содержать всего один элемент, и этот элемент будет массивом. Чтоб было понятнее о чём я говорю, попробуйте в консоли браузера выполнять следующее: let arr1 = [], arr2 = [1,2,3]; arr1.push(arr2); console.log(arr1);

    Но вобще весь getAll() можно сделать проще:

    public getAll(): Promise<Room[]> {
        return axios.get<Room[]>('somepath/kek:1488?SeigHeil&joking=true')
          .then(response => response.data)
          .catch(err => console.log(err))
    }


    Так же проще?

    C axios никогда не работал, так что этот ответ может быть полной лажей. Но попробуйте предложенный вариант. Судя по описанию типов, всё должно получиться как ожидается.
    Ответ написан
  • Как импортировать js файл в TypeScript проект?

    search
    @search
    мама говорит что я особенный
    Опишите интерфейс библиотеки в .d.ts файле. Назовите этот файл как-нибудь типа global.d.ts и положите в корень проекта (там где все ts файлы лежат, обычно это папка /src). Подробнее можно почитать тут https://basarat.gitbooks.io/typescript/docs/types/... . Вот полная документация https://www.typescriptlang.org/docs/handbook/decla... .

    Сам файл будет выглядеть как-то так:

    // global.d.ts
    declare function ConfigService();
    Ответ написан
  • Что важно знать в TypeScript для быстрого старта c Angular4+?

    search
    @search
    мама говорит что я особенный
    Все эти знания принесут пользу несомненно, но они не критичны. Ангуляр весьма органично дружит с тайпскриптом и не требует никакой экзотики. С перечисленными темами можно ознакомиться по ходу пьесы если будет интересно. К вашему списку можно добавтьб дженерики (Generics), они часто используются в ангуляре и желательно понимать что это такое.

    Что нереально важно для комфортной работы с ангуляром, так это RxJS. Rx представляет декларативный подход к программированию и на первых парах полностью выносит мозг. Правда потом не знаешь как без него жить дальше. Непонимание RxJS - это гарантия провала и обиды на фреймворк. Вот это видео может немного пролить свет https://www.youtube.com/watch?v=3LKMwkuK0ZE . Не теряйте времени зря и разберитесь в теме заранее, чтоб потом не жалеть о напрасно написанном коде.

    Еще, как и большинство фреймворков, ангуляр не поставляет менеджер состояния по умолчанию. Неокрепшие умы хранят глобальное состояние прямо в сервисах. Что мало чем отличается от использования глобальных переменных. Но для глобальных состояний существует NgRx. Это Redux на стероидах. Опять же, прийдётся с этим разобраться для того чтоб через год не оказаться у разбитого корыта.
    Ответ написан
    4 комментария
  • Как отключить ошибки tslint при компиляции проекта?

    search
    @search
    мама говорит что я особенный
    Можно. Добавьте в конфиг tslint'a `"defaultSeverity": "warning"`.
    Ответ написан
    Комментировать
  • RxJs: условный mergeMap в pipe?

    search
    @search
    мама говорит что я особенный
    // Да, сначала мы делаем map, потому что он делается полюбому:
    
    let doSomething$ = this.myApi.getSomething(id).pipe(
      map(tags => ({ ...updatedShop, tags }))
    )
    
    // А затем мы делаем mergeMap если понадобится:
    
    if (shop.isNew) {
      doSomething$ = doSomething$.pipe(
        mergeMap(() =>
                      this.myApi.addTags(updatedShop.id, shop.tags).pipe(
                          map(() => {
                              return {
                                  ...updatedShop,
                                  tags: shop.tags
                              };
                          })
                      )
                  )
      )
    }
    
    // ну и затем подписываемся на это дело чтоб оно начало работать:
    
    doSomething$.subscribe();


    Вам будет значительно легче понять RxJS после просмотра вот этого видео: https://www.youtube.com/watch?v=3LKMwkuK0ZE Оно слега отстало от времени (операторы к обозревателю теперь добавляются через функцию pipe()), но сами принципы, описанные в видео, никуда не делись.

    UPD

    Если код выше повергает вас в тоску, то можно сделать так:

    this.myApi.getSomething(id).pipe(
      map(tags => ({ ...updatedShop, tags })),
      mergeMap((tags) => {
        if (!shop.isNew) {
          return of(tags);
        }
       return this.myApi.addTags(updatedShop.id, shop.tags).pipe(
                          map(() => {
                              return {
                                  ...updatedShop,
                                  tags: shop.tags
                              };
                          })
                      )
      }),
    )


    Имеется ввиду, что можно иф вынести в сам mergeMap. И если магаз не новый, то возвращать обзёрвбл от магаза, а если новый, то сделать что-то там еще.
    Ответ написан
    1 комментарий
  • Как мне преобразовать полученный json в массив, который я бы мог прогнать через ngFor?

    search
    @search
    мама говорит что я особенный
    Не нужно result.json()

    Данные уже там.

    result.data достаточно.

    (при условии что вы используете Angular > 4.3)
    Ответ написан
  • Ошибка в TypeScript, как пофиксить?

    search
    @search
    мама говорит что я особенный
    Уберите эту часть

    constructor(props: Props) {
        super(props);
      }


    Этот код выполняется автоматически в классе React.Component. Его не нужно дублировать.

    UPD

    А вообще код слегка странный. Я так понимаю что App у вас главный компонент. Предполагаю что он рисуется в файле index.ts. Вашему App точно нужны props? Если нужны, то их нужно передать. Как-то вот так:

    <App props={} />
    Ответ написан
  • TypeScript import из сабдериктории?

    search
    @search
    мама говорит что я особенный
    Если предполагается что `someFunc` хранится в своём отдельном файле, то в `Navigator/index.ts` должна быть строчка `export * from './some-func'`. Где some-func - имя файла.
    Ответ написан
    Комментировать
  • Почему subscribe() не видит nativeElement?

    search
    @search
    мама говорит что я особенный
    Потому что на момент выполнения кода в subscribe(), элемента с id=graph еще не существует. *ngIf отрисует этот элемент не мгновенно после this.trainings = trainings, а только после выполнения функции subscribe().

    Для того чтоб код не имел неприятного запаха из-за setTimeout(), можно передавать trainings в GraphComponent извне. Тогда это будет выглядеть как-то так:

    <app-graph  [trainings]="trainings" *ngIf="trainings.length"></app-graph>
    Ответ написан
    Комментировать