Ответы пользователя по тегу TypeScript
  • Зачем нужен @typescript-eslint/parser?

    Aetae
    @Aetae Куратор тега TypeScript
    Тлен
    Если конфиг унаследован от "plugin:@typescript-eslint/recommended", то не нужен, он просто там уже прописан.

    Суть же в том, что тебе может не понравиться набор правил recommended и ты можешь его выкинуть, набросав свой по вкусу. И тогда всё сломается. Потому лучше указывать парсер сразу явно.
    Ответ написан
    3 комментария
  • Почему reject возвращает тип unknown?

    Aetae
    @Aetae Куратор тега JavaScript
    Тлен
    Понавертели лишнего.
    Во-первых: есть хэлперы Promise.reslove(data) и Promise.reject(error), а во-вторых: при возврате из then\catch даже они не нужны.
    interface ResponseData {
      status: boolean;
      data?: object;
    }
    
    function sendQuery(url: string, data: object): Promise<ResponseData> {
      return fetch(url, {
        method: "POST",
        headers: {
          Accept: "application/json",
          "Content-Type": "application/json"
        },
        body: JSON.stringify(data)
      }).then(response => 
        response.json()
      ).then(data => ({
        status: true,
        data: data
      })).catch(() => {
        throw {
          status: false
        }
      });
    }


    Хотя ваш вариант НЕ неправильный, просто бессмысленно перегруженный, проблема в том, что TS, увы, не может автоматически вывести тип конструкции new Promise, а потому выдаёт Promise<unknown>. Т.е. каждый раз, когда вы используете new Promise - надо использовать его с дженериком: new Promise<Type>.
    Ответ написан
    Комментировать
  • Как скомпилировать несколько файлов в разных директориях и результат компиляции так же разложить по разным директориям?

    Aetae
    @Aetae Куратор тега TypeScript
    Тлен
    Сам tsc же билдит по умолчанию файлы 1 к 1. Это сборщики потом собирают всё воедино. Решение - не использовать сборщик.)
    Если цель только самое современное, можно вообще юзать target esnext, script type="module" и свежую ноду с поддержкой esm.)
    Ответ написан
  • Как исправить ошибку "No index signature..." при обращении к свойствам объекта?

    Aetae
    @Aetae Куратор тега TypeScript
    Тлен
    const queryKey: AuthMessagesKeys = queryObject.message

    Это сработает, но не надёжно - потому что может упасть в рантайме если в message прилетит что-то левое.
    Лучше написать тайпгард, типа
    function isAuthMessagesKey(str: string): str is AuthMessagesKeys {
      return ['login', 'logout', 'session'].includes(str); 
    }

    и делать проверку перед использованием.
    Ответ написан
    Комментировать
  • Как правильно выполнить типизацию кода на React (children и ответ при асинхронном запросе)?

    Aetae
    @Aetae Куратор тега TypeScript
    Тлен
    1. У реакта есть хэлпер PropsWithChildren<Props>. Но под капотом он просто делает так:
    type PropsWithChildren<P> = P & { children?: ReactNode };

    ...upd: вник чутка)
    Если тебе нужен render проп в children, то явно и тапизируй, никаких подвохов:
    type TwitterProps = {
        children: (user: string) => ReactNode
    }

    2. Так и типизировать: const response: ITwitter = .... Только если какая-нить хрень прилетит то может сломаться в рантайме, так что либо ты доверяешь серверу, либо используешь какую-нить либу для дополнительной проверки вживую.)
    Ответ написан
    Комментировать
  • Как перезаписать поля HTMLElement полями из входного объекта в Typescript?

    Aetae
    @Aetae Куратор тега TypeScript
    Тлен
    Яб сделал так:
    type WritableFields<T> = Partial<Pick<T, WritableKeys<T>>>;
    export function createElement<K extends keyof HTMLElementTagNameMap>(tag: K, options?: WritableFields<HTMLElementTagNameMap[K]>): HTMLElementTagNameMap[K] {
      let element = document.createElement(tag)
    
      if (options) {
        // assign options
        Object.assign(element, options);
      }
    
      return element
    }


    Если нужно именно с перебором, то можно так:
    type WritableFields<T> = Partial<Pick<T, WritableKeys<T>>>;
    export function createElement<K extends keyof HTMLElementTagNameMap>(tag: K, options?: WritableFields<HTMLElementTagNameMap[K]>): HTMLElementTagNameMap[K] {
      let element = document.createElement(tag)
    
      if (options) {
        // assign options
        let option: keyof typeof options;
        for (option in options) {
          element[option] = options[option]!; // ! - потому что теоретически ты можешь передать undefined явно, но морочиться с этим не стоит
        }
      }
    
      return element
    }


    P.S. Вообще все сложности с перебором переданного объекта в typescript происходят из того, что типизация в нём структураная: например имея интерфейс параметра, например,
    interface Foo {
      foo: number;
    }
    тебе ничего не мешает передать ему
    {
      foo: 1,
      bar: 2
    }
    , т.к. данный объект расширяет интерфейс Foo и, соответственно, удовлетворяет ему. Получается, что внутри функции typescript никак не может быть уверен, что ключи указанные в интерфейсе - это ВСЕ ключи, а значит не может быть уверен, что при переборе и присвоении не будет присвоено что-то лишнее. (Это не говоря уже о прототипах, геттерах и прочем)
    Потому и требуется куча плясок, увы.
    Ответ написан
    6 комментариев
  • Почему выдает ошибку Nuxt + TypeScript?

    Aetae
    @Aetae Куратор тега TypeScript
    Тлен
    Вы использовали инструкцию или просто рандомно подключили TypeScript к Nuxt?
    Дело в том, что Nuxt много чего подключает неявно, в т.ч. и роутер, и потому TypeScript не знает о том, что в типе Vue появились дополнительные свойства типа $route. Надо отдельно подключать декларации вручную, либо следовать инструкции выше.
    Ответ написан
    Комментировать
  • Почему не распознаётся команда tsc?

    Aetae
    @Aetae Куратор тега TypeScript
    Тлен
    Если ты ставил его глобально через npm или yarn - то должно работать сразу.
    Чтобы установленное подтянулось часто надо перезапустить терминал, возможно в этом дело.)
    Ответ написан
    Комментировать
  • Почему нет ошибки при присваивании массива из других интерфейсов?

    Aetae
    @Aetae Куратор тега TypeScript
    Тлен
    В ts структурная типизация. Такое может происходить если Snapshot структурно укладывается в тип Volume.

    Т.е. вот так типы взаимозаменяемы:
    interface Volume {
     id: number;
     volume?: string;
    }
    
    interface Snapshot {
     id: number;
     snapshot?: string;
    }
    А так нет:
    interface Volume {
     id: number;
     volume: string;
    }
    
    interface Snapshot {
     id: number;
     snapshot: string;
    }

    И так нет:
    interface Volume {
     id?: number;
    }
    
    interface Snapshot {
     id?: string;
    }
    Ответ написан
    Комментировать
  • Как затипизировать метод?

    Aetae
    @Aetae Куратор тега TypeScript
    Тлен
    Хотелось бы знать, что за тип такой Constants, возможно всё можно сделать проще.
    Но условно - как-то так:
    enum Constants {
      VERTICAL = 'vertical',
      STEP = 'step'
    }
    
    interface ConstantsTypes {
      [Constants.VERTICAL]: boolean,
      [Constants.STEP]: number,
    }
    
    public get<T extends keyof ConstantsTypes>(prop: T): ConstantsTypes[T] {}
    Ответ написан
    Комментировать
  • Почему не работают интерфейсы?

    Aetae
    @Aetae Куратор тега JavaScript
    Тлен
    В обзем шляпа у них с документацией и примерами. Ни в одном примере они не используют объекты вообще, также как нигде нет ни одного примера типизированного объекта. Из чего могу сделать вывод, что с типизированными объектами они не могут работать вообще. Но это не точно.

    Работает например подобная херотень:
    export class IResultItem {
      constructor(
        public id: i32,
        public type: string,
        public date: string,
        public from: string,
        public from_id: i32,
        public text: string
      ) {}
    }
    export function add(
      result: IResultItem[] = [new IResultItem( 1, "type", "25.25.2025", "rew", 123, "hello" )]
    ): IResultItem[] {
    return result;
    }
    Ответ написан
    Комментировать
  • Как можно ограничить интерфейс только методами?

    Aetae
    @Aetae Куратор тега TypeScript
    Тлен
    Тут понадобится немного магии:
    type ClearIndex<T> = {
      [ P in keyof T as string extends P ? never : P ] : T[P]
    };
    class FOO implements ClearIndex<Service_FOO > {
        methodFoo() {}
    }


    Суть проблемы в том что Record<string, () => void> имеет "index signature", т.е. заявляет, что обращение по любому ключу stringвернёт () => void.
    Service_FOO расширяет этот тип(а не сужает), потому Service_FOO имеет ту же index signature и уточнённый конкретный метод.
    Класс же в ts не может иметь index signature, т.к. является строгой и конкретной структурой.
    Ответ написан
    2 комментария
  • Как решить Parsing Error в ESLint?

    Aetae
    @Aetae Куратор тега TypeScript
    Тлен
    jsx, полагаю, мозги парит. Не юзайте jsx с vue. Хоть это и разрешено, но jsx такое уродливое дерьмо по сравнению с нормальными vue-шаблонами...
    Ответ написан
  • Что может ESLint без плагинов?

    Aetae
    @Aetae Куратор тега JavaScript
    Тлен
    ESlint без плагинов может довести до нервного срыва.
    Ответ написан
    Комментировать
  • [TypeScript] Можно ли создать тип из ключей объекта?

    Aetae
    @Aetae Куратор тега TypeScript
    Тлен
    Можно, если им явно не указать тип Args, но тогда вы теряете предварительную проверку, увы:
    let a1 = {
        channelID: {
            RegExp: ["\\d+", true],
            description: "d1"
        },
        content: {
            RegExp: [".+", true],
            description: "d2"
        }
    };
    type T1 = {[K in keyof typeof a1]: string}


    Чтобы сохранить проверку - придётся воспользоваться дополнительной бессмысленной функцией для уточнения типа:
    type Args = {
        [key: string]: {
            RegExp: [string, boolean],
            description: string
        }
    }
    function createArgs<T extends Args>(args: T): T {
        return args;
    }
    
    type TStringKeys<T extends Args> = {[K in keyof T]: string};
    
    
    let a1 = createArgs({
        channelID: {
            RegExp: ["\\d+", true],
            description: "d1"
        },
        content: {
            RegExp: [".+", true],
            description: "d2"
        }
    });
    
    type T1 = TStringKeys<typeof a1>
    К сожалению на текущий момент(ts4.2.3) избавиться от функции-обёртки не получится.
    Ответ написан
    1 комментарий
  • Как правильно выполнить типизацию функции трансформации данных?

    Aetae
    @Aetae Куратор тега TypeScript
    Тлен
    interface IOrder {
        date: string,
        docTypesName: string,
        docId: number,
        image: string,
        name: string,
        price: number,
        quantity: number,
        removed: number,
    }
    
    interface  IProduct {
        image: string,
        name: string,
        price: number,
        quantity: number,
    }
    
    interface IDocument {
        date: string,
        docId: number,
        docTypesName: string,
        products: IProduct[],
    }
    
    interface IElement {
        date: string,
        documents: IDocument[]
    }
    
    interface IElementMap {
        date: string,
        documents: Record<string, IDocument>
    }
    
    type IResultMap = Record<string, IElementMap>;
    
    function f(orders: IOrder[]): IElement[] {
        const result = orders.reduce((accumulator, currentValue) => {
            const date = currentValue.date.split(' ')[0];
    
            if (!accumulator[date]) {
                accumulator[date] = {
                    date,
                    documents: {},
                }
            }
    
            if (!accumulator[date].documents[currentValue.docTypesName]) {
                accumulator[date].documents[currentValue.docTypesName] = {
                    date: currentValue.date,
                    docId: currentValue.docId,
                    docTypesName: currentValue.docTypesName,
                    products: [],
                }
            }
    
            accumulator[date].documents[currentValue.docTypesName].products.push({
                name: currentValue.name,
                price: currentValue.price,
                image: currentValue.image,
                quantity: currentValue.quantity,
            })
    
            return accumulator;
        }, {} as IResultMap)
    
        console.log('result', result);
    
        return Object.values(result).map(currentValue => {
            console.log('currentValue', currentValue);
    
            return {
                ...currentValue,
                documents: Object.values(currentValue.documents)
            }
        });
    }
    
    console.log(f(orders));
    Ответ написан
    Комментировать
  • Как лучше всего распарсить нетипизированный JSON?

    Aetae
    @Aetae Куратор тега TypeScript
    Тлен
    Не очень понятен вопрос, но если проблема в типизпции json то в гугле полно json to ts генераторов, которые нaгенерят тебе нужные интерфейсы. Также есть библиотеки, которые позволят тебе этот вопрос автоматизировать и рантайм-хэлперы. И, наконец, если сервер предоставляет свою спеку в open api(swagger), есть генераторы, которые сгенеруруют тебе сразу весь нужный обвес в т.ч. для angular.
    Ответ написан
    Комментировать
  • NextJS: Как импортировать JS-библиотеки?

    Aetae
    @Aetae Куратор тега JavaScript
    Тлен
    import './my-library.js'; // без from

    Если без allowJs, то ещё докинуть файлик my-library.d.ts с деклакрициями:
    declare let var1: number;
    declare function fn1(): void;
    // ...
    Ответ написан
  • Как в TypeScript описать массив массивов с объектами внутри?

    Aetae
    @Aetae Куратор тега TypeScript
    Тлен
    Array<Array<Record<string, string>>>
    Ответ написан
    Комментировать
  • Как убрать предупреждение TypeScript?

    Aetae
    @Aetae Куратор тега TypeScript
    Тлен
    Хз, что за fastify но если он поддерживает и js и ts - может оставить заботу о типах на того, кто захочет использовать ваш плагин(хоть это и моветон).
    Если он использует только ts, то используя его, вы, очевидно, должны знать ts. В такому случае сделайте именно то, что вам пишет консоль: сделайте соответствующий файл декларации.
    Ответ написан