Задать вопрос
Ответы пользователя по тегу TypeScript
  • Проблемы с типами при наследовании от абстрактного класса или при импликации от интерфейса?

    Aetae
    @Aetae Куратор тега JavaScript
    Тлен
    Ну потому что extend - это "расширение", и главное совместимость, м?

    В данном случае любой UserInfo обратно совместим с BaseUserInfo, т.к. для BaseUserInfo.getState() возвращаемое значение имеет тип void (не путать с undefined), который никак не может быть использован (сам ts не даст).
    abstract class BaseUserInfo {
      abstract getState(): void;
    }
    
    class UserInfo extends BaseUserInfo { 
      override getState = (): number => 1;
    }
    
    function useInfo(info: BaseUserInfo) {
      // An expression of type 'void' cannot be tested for truthiness.(1345)
      if (info.getState()) { // не получится так сделать и всё сломать
        console.log('never')
      }
    }
    Ответ написан
    Комментировать
  • Как правильно написать enum в React Typescript?

    Aetae
    @Aetae Куратор тега TypeScript
    Тлен
    Ну какбэ очевидно, что в item.deviceType у тебя строка, а не DeviceType. Проверь что у тебя там в item.
    Ответ написан
  • Как типизировать значение?

    Aetae
    @Aetae Куратор тега TypeScript
    Тлен
    Если ты не указываешь при useState тип стейта руками, то он выводится автоматически.

    useState([null, null]); - ts выведет тут тип null[], то есть массив null, про Date он никак догадаться не может. Следует указать явно: useState<Array<Date | null>>([null, null]);
    Ответ написан
    3 комментария
  • Как правильно записать проверку контекста next-redux-wrapper?

    Aetae
    @Aetae Куратор тега TypeScript
    Тлен
    Глубоко не вникал, но наверное тут логично испрользовать тайп гарды:
    // какая-то проверка достаточная чтобы сказать, что у нас тут NextPageContext;
    const isNextPageContext = (ctx: unknown): ctx is NextPageContext => false; 
    // аналогично для AppContext
    const isAppContext = (ctx: unknown): ctx is AppContext => false; 
    
    const baseQuery = fetchBaseQuery({
      baseUrl: 'http://localhost:7777/api/auth',
      prepareHeaders: (headers, { extra }) => {
        let req;
    
        if (isNextPageContext(extra)) {
          req = extra.req;
        } else if (isAppContext(extra)) {
          req = extra.ctx?.req;
        }
    
        if (req) {
          headers.set('Cookie', req.headers.cookie || '');
        }
    
        return headers;
      },
      credentials: 'include',
    });
    Ответ написан
    Комментировать
  • Как сделать возврат последнего успешного значения и retry вместе с delay в случае ошибки?

    Aetae
    @Aetae Куратор тега TypeScript
    Тлен
    Как-то так (не проверял):
    interface CreateConnectionOptions extends ConnectOptions {
      retryCount?: number;
      retryDelay?: number;
    }
    
    function createConnection(uri: string, {
      retryCount = 6,
      retryDelay = 1000,
      ...mongooseConnectOptions
    }: CreateConnectionOptions = {}): Observable<Connection> {
      let connection$ = defer(() => mongoose.createConnection(uri, mongooseConnectOptions).asPromise());
      
      if (retryCount > 0) {
        connection$ = connection$.pipe(retry({
          count: retryCount,
          delay: retryDelay
        }));
      }
      
      return connection$.pipe(shareReplay(1));
    }
    Ответ написан
    Комментировать
  • Как типизировать огромный объект в typescript?

    Aetae
    @Aetae Куратор тега TypeScript
    Тлен
    Если объект уже есть, то его самого можно использовать как тип.
    const obj = { ... }; 
    type Obj = typeof obj;

    Если объекта нет, но у входящего объекта должны быть конкретные ключи и ты хочешь их проверять, то без задания полноценного интерфейса с прописыванием каждого - никак, ведь проверять каждое поле ты и хочешь. Онлайн полно генераторов, которые сделают тебе из json интерфейс, останется только довести.

    Если поля поддаются какой-то логике, то с использованием литералов можно сделать компактный тип.
    Ответ написан
    Комментировать
  • Возможно ли реализовать более изящную типизацию объектов и деструктивное присваивание?

    Aetae
    @Aetae Куратор тега JavaScript
    Тлен
    А ты для начала придумай синтаксис для этого, который бы не вступал в прямой кофликт с JS и при этом был интуитивен.)
    Вот тут на тему много копий сломано, но, ИМХО, нет нормальных достойных релиза вариантов.)
    Ответ написан
    Комментировать
  • Как в TypeScript, добавлять свойство по условию?

    Aetae
    @Aetae Куратор тега TypeScript
    Тлен
    Нужно больше чёткости. Какой ещё бывает view кроме labled?
    Через интерфейсы это сделать нельзя - можно через union типов, но обязательно должно быть поле-дискриминатор, различное для каждого случая.

    Если такого поля нет - конкретный тип сделать нельзя, однако судя по приставке Props, можно предположить, что это какие-то props какого-то React компонента, тогда этого можно добиться с помощью перегрузки:
    export interface ModalProps extends CuiModalProps {
        children: ReactElement | ReactElement[]
        setterClosePopup: Dispatch<SetStateAction<boolean>>
        namePopup?: string
        isOpen?: boolean
        withBorder?: boolean
        className?: string
    }
    export interface ModalPropsLabled extends ModalProps {
        view: 'labeled'
        label: string
    }
    
    export const Component: ((pros: ModalProps) => ReactNode) & ((pros: ModalPropsLabled) => ReactNode) = (pros: ModalProps | ModalPropsLabled) => { ... }
    Ответ написан
  • Стоит ли вносить константы в класс?

    Aetae
    @Aetae Куратор тега TypeScript
    Тлен
    Константы в классе - нормальная практика, однако они должны быть static, нечего их в каждом инстансе дублировать.
    Ответ написан
    Комментировать
  • Как правльно использовать TS в монорепе?

    Aetae
    @Aetae Куратор тега TypeScript
    Тлен
    Все интерфейсы что должны быть публичными - должны быть экспортированы в корне @company/core, точно также как и все модули.
    Ответ написан
    1 комментарий
  • В чем причина ts ошибки при передаче пропсов в компонент?

    Aetae
    @Aetae Куратор тега TypeScript
    Тлен
    Где-то среди >260 свойств из React.ComponentPropsWithRef<'select'> находится свойство, которое дженерик Option в Select устанавливает как string | number с большим приоритетом, чем то что ты кладёшь собственно в Options. Можешь поискать сам убирая по одному или сравнивая с декларацией для Select.

    Но в принципе решение просто выкинуть React.ComponentPropsWithRef<'select'>, т.к. ты расширяешь не нативный select, а react-select.
    import Select, { Props } from 'react-select';
    
    interface ISelectProps extends Props<OptionType> {
        caption?: string;
        disabled?: boolean
    }
    Ответ написан
  • Как лучше сделать экспорт класса, чтобы вызывать его как функцию?

    Aetae
    @Aetae Куратор тега TypeScript
    Тлен
    Вам лень писать new? Имхо, это перебор. Не отвалятся у вас руки три лишних символа написать, и это будет куда нагляднее чем непонятные излишние функции.

    Но рас так хочется, то тип для твоей функции таков:
    function exportConstruct<P extends any[], T>(classFromExport: { new (...args: P): T; }): 
    (...args: P) => T {
      return (...args) => new classFromExport(...args);
    }

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

    Если можешь использовать Proxy то можно просто сделать класс вызываемым:
    function exportCallable<T extends { new (...args: any[]): any; }>(classFromExport: T) {
      return new Proxy(classFromExport, {
        apply(ctor, _, args) {
          return new ctor(...args);
        }
      }) as T & ((...args: ConstructorParameters<T>) => InstanceType<T>);
    }
    
    const Lol = exportCallable(class Lol extends BaseLol {
      constructor(public name: string) {
        super();
        this.name = name.toUpperCase();
      }
    });
    
    Lol('qwe');


    Либо ты можешь просто добавть статический метод, который будет делать то же самое:
    abstract class Newable {
      static new<P extends any[], T>(this: { new (...args: P): T; }, ...args: P): T { 
        return (new this(...args)) as T
      }
    }
    
    class BaseLol extends Newable {  /* ... */ }
    
    class Lol extends BaseLol {
      constructor(public name: string) {
        super();
        this.name = name.toUpperCase();
      }
    }
    
    Lol.new('qwe');
    Ответ написан
  • Как указать в TypeScript интерфейсе, что в массиве могут содержаться много однотипных объектов?

    Aetae
    @Aetae Куратор тега TypeScript
    Тлен
    [ {title: string, cardList: []} ] - это не массив, заполняемый значениями типа {title: string, cardList: []}, это кортеж из одного значения данного типа.
    Массив обозначается так Array<{title: string, cardList: []}> или так {title: string, cardList: []}[].
    Кортеж используется когда нужно конкретное количество значений конкретного тип на конкретных позициях.
    Ответ написан
    1 комментарий
  • Почему не получается создать тип Object[] в typescript?

    Aetae
    @Aetae Куратор тега TypeScript
    Тлен
    В данном случае T значит любой конкретный тип который extends Object[].
    например new A<[{c: 3}]>() - абсолютно валидно, при этом в public B уже не может быть того что ты туда положил.
    Ответ написан
    Комментировать
  • Как переназначить функцию console.log в nodejs?

    Aetae
    @Aetae Куратор тега TypeScript
    Тлен
    Вынеси свою подмену в отдельный модуль и делай его require\import ДО импорта той библиотеки.
    Правда не факт что либа использует именно console.log, а не stdout напрямую.
    Ответ написан
    Комментировать
  • Как правильно затипизировать данный кусок кода?

    Aetae
    @Aetae Куратор тега TypeScript
    Тлен
    Если не используете Node.js то просто исключите типы для неё из конфига TS.
    Тогда у вас setTimeout будет возвращать простой number, а clearTimeout будет принимать number | undefined. И никаких проблем.)

    Если же код ноды по каким-то причинам у вас идёт вперемешку со фронтовым кодом, то для фронтовых таймеров можете писать явно window.setTimeout и window.clearTimeout.
    Ответ написан
    Комментировать
  • TypeScript. Как сделать оверлоад объекта стрелочной функции?

    Aetae
    @Aetae Куратор тега TypeScript
    Тлен
    ТС недостаточно умный для этого. Решает он так, потому что когда ты делаешь SomeType extends BaseType для аргумента функции, внутри функции значение этого аргумента просто BaseType и автоматический вывод исходит из этого. Тут либо добавлять руками оверлоады и на враппер, или пробовать писать головоломный тип, или обойтись без оверлоадов явными условиями типа:
    type MyFuncAs =<T extends boolean> (obj?: Obj<T>) => T extends false ? number : string;
    Ответ написан
    1 комментарий
  • Vetur отключить предуприждение стилистики?

    Aetae
    @Aetae Куратор тега TypeScript
    Тлен
    В каком-ниюудь модуле укажи:
    declare global {
      const VUE_APP_WS_URL: string | undefined;
    }

    В тайпскрит всё должно быть типизированнно. Ты не можешь просто с потолка брать какие-то переменные.
    Ответ написан
    Комментировать
  • Где размещать тесно связанные типы typescript?

    Aetae
    @Aetae Куратор тега TypeScript
    Тлен
    Не слушай Василий Банников, плодить копипаст-типы точно не надо.

    А по размещению типов точно такая же логика как с обычными модулями. Так что абсолютно нормально импортировать связанные типы из связанного модуля. Все теории и паттерны проектирования применяются и тут.

    По хорошему конечно стоит придерживаться SOLID или чего-то подобного.
    Т.е. в Grid сделать тип IGridItemProps с теми свойствами которые точно нужны для работы Grid, а в GridItem наследовать от него уже конкретную реализацию
    interface GridItemProps extends IGridItemProps { ... }
    . Однако это нужно только если теоретически могут появиться ещё GridItemSuper и GrigItemNice, если же такого быть не может и модули(компоненты) сами по себе тесно связны, то заморачиваться не стоит.
    Ответ написан
  • Как реализуется enum в JS из Typescript?

    Aetae
    @Aetae Куратор тега JavaScript
    Тлен
    Потому что enum в typescript может мержиться:
    Валидный код:
    enum Membership {
      Simple,
      Standart,
      Premium
    }
    
    enum Membership {
      SimpleX = 99
    }

    Почему компилятор не собирает его воедино, если такие штуки тока на этапе компиляции работают - я хз, но наверное есть причины.
    Ответ написан
    3 комментария