Ответы пользователя по тегу TypeScript
  • Для чего setTimeout возвращает разные типы?

    Aetae
    @Aetae Куратор тега TypeScript
    Тлен
    В Node.js setTimeout имеет иную сигнатуру. Если не используете node.js - исключите её типы из tsconfig. Ну или пишите wimdow.setTimeout как советовали в комментах, тем самым указывая на объект window который есть только в браузере.
    Ответ написан
  • Не удается найти модуль "./App.vue" или связанные с ним объявления типов. Vue.js 3 и TypeScript?

    Aetae
    @Aetae Куратор тега TypeScript
    Тлен
    Стандартная какашка, которая идёт в комплекте с любым готовым пресетом, файлик vue.d.ts с содержимым:
    declare module '*.vue' {
      import type { DefineComponent } from 'vue';
      const component: DefineComponent<{}, {}, any>;
      export default component;
    }
    Ответ написан
    Комментировать
  • Почему ругается Vscode на типы?

    Aetae
    @Aetae Куратор тега TypeScript
    Тлен
    Ну потому что это union - он строгий, он позволяет получать свойство напрямую только в том случае, если оно есть у всех членов union'а. В ином случае надо руками делать проверку, которая сузит тип до нужного. if ('counter' in ...) и т.п.
    Ответ написан
    Комментировать
  • Как использовать TypeScript в существующем проекте Strapi?

    Aetae
    @Aetae Куратор тега TypeScript
    Тлен
    Typescript тут не при чём, ошибка у тебя в рантайме, когда никакого тайпскрипта уже нет.
    В чём ошибка - написано у тебя прямо в консоли. Но если способность читать у тебя работает только на форумах, растолкую:
    Strapi пытается прочитать поле routes у несуществующего(undefined) объекта. Почитай документацию и найди куда ты там должен положить какие-то routes.
    Ответ написан
    4 комментария
  • Не работает Vue.use(Vuex) в файле store.ts, как исправить?

    Aetae
    @Aetae Куратор тега TypeScript
    Тлен
    В Vue 3 нет никакого Vue.use(), теперь все плагины ставятся не глобально, а в конкретное приложение:
    import { createApp } from 'vue'
    import { createStore } from 'vuex'
    
    // Create a new store instance.
    const store = createStore({
      state () {
        return {
          count: 0
        }
      },
      mutations: {
        increment (state) {
          state.count++
        }
      }
    })
    
    const app = createApp({ /* your root component */ })
    
    // Install the store instance as a plugin
    app.use(store)
    (из официальной документации vuex)

    Ну и modelair верно сказал - теперь топят за pinia вместо vuex, что и к лучшему, так как по сути выкинули весь оверинжинирнутый мусор из vuex оставив только осмысленный функционал.
    Ответ написан
    Комментировать
  • Как сделать фабрику миксинов?

    Aetae
    @Aetae Куратор тега TypeScript
    Тлен
    Без вариантов. Мешать классы в ts незя, потому что он как и js не поддерживает множественное наследование. Все методы сбоку через прототипы - не подразумевают работу с классами.
    Помимо того что сам js физически не даст тебе работать с нативными приватными свойствами(#), так уже ts не даст тебе работать нормально с приватными и защищёнными(private и protected), а микс абстрактных (abstract) вообще забагован и не работает(issue у них пару лет висит на гитхабе).

    В общем только крайне ограничено.
    Ответ написан
  • Как импортировать переменные в react?

    Aetae
    @Aetae Куратор тега TypeScript
    Тлен
    Ну в принципе можно как с любыми переменными - вынести за компонент, и даже будет работать, но так делать не надо.)

    Нормальное решение - использовать context всесто ref. Сверху где-то его Provider зафигачить, а где надо useContext.
    Ответ написан
    Комментировать
  • Почему тайпскрипт неправильно считывает тип?

    Aetae
    @Aetae Куратор тега TypeScript
    Тлен
    Скорее всего поможет перегрузка, что-то типа:
    function getSkills(params: TGetSkills['requestParams']): TGetSkills['response'];
    function getSkills(params: TGetSkillsWithCriterions['requestParams']): TGetSkillsWithCriterions['response'];
    function getSkills(
        params: (TGetSkills | TGetSkillsWithCriterions)['requestParams'],
      ) {
        return instance.get<(TGetSkills | TGetSkillsWithCriterions)['response']>('url', {
          params: params,
        }),
    }
    
    getSkills: getSkills
    Ответ написан
    1 комментарий
  • Как реализовать DI как в ангуляре?

    Aetae
    @Aetae Куратор тега TypeScript
    Тлен
    Во первых DI в js\ts - полная бессмысленная хуита. Просто импортируй по-человечески что надо и используй.

    Но если очень хочется - это сложно. Механизм DI не предусмотрен в парадигме языка. Тебе придётся использовать свою особую надстройку над системой сборки, которая найдёт в файлах подобные DI и заменит их на обычные человеческие импорты. Сделать можно это тремя основными способами: как трансформермер для typescript, как трансформермер для babel и как кастомный loader для webpack. Во всех случаях это включает в себя работу с AST и кодогенерацию на этапе сборки.

    Впрочем, в залежах npm наверняка можно нарыть что-то готовое, чтоб не писать самому.
    Ответ написан
  • Как резольвить алиасы у скаченного через package.json репозитория?

    Aetae
    @Aetae Куратор тега TypeScript
    Тлен
    Очевидно что пакет битый или ты подключаешь что-то не то.
    В готовой либе никаких алиасов быть не должно, на то она и готовая.

    Можно что-то нашаманить, но в каждом конкретном случае своё, потому что в любом случае через жопу.
    Ответ написан
    Комментировать
  • Как правильно объединить два типа HTMLElement?

    Aetae
    @Aetae Куратор тега TypeScript
    Тлен
    Ответ Александр хорошо работает если есть дискриминатор (в приведённом примере поле type).

    Если же такого уникального поля нет, то конкретно для React можно сделать на перегрузках, условно:
    type ExtraProps = {
      size?: 's' | 'm' | 'l';
    }
    
    type AnchorProps = ExtraProps & {href: string};
    type ButtonProps = ExtraProps & {type: string};
    
    function TappableComponent(props: AnchorProps ): ReactNode; 
    function TappableComponent(props: ButtonProps ): ReactNode;
    function TappableComponent(props: AnchorProps | ButtonProps ) {
         const Component = 'href' in props ? 'a' : 'button';
         return <Component>...</Component>
    }

    Там множество подводных камней, но иногда удобно.
    Ответ написан
    Комментировать
  • TypeScript ругается на getAttribute('href'). Как получить href ссылки?

    Aetae
    @Aetae Куратор тега TypeScript
    Тлен
    Ради ускорения сборки из коробки не предусмотрено сложной типизации событий. Одно время события имели сложную типизацию на дженериках, но оную вкинули из ts. (Что весьма меня расстраивает, могли бы и оставить как отдельную настройку, для тех кому плавная типизация важнее скорости.)

    Тебе остаётся только кастовать типы руками, увы. Причём рекомендую в данном случае использовать currentTarget а не target, потому что target может оказаться например span внутри этой ссылки, а не она сама.
    Ответ написан
  • Типизировать src,The expected type comes from property 'src' which is declared here on type?

    Aetae
    @Aetae Куратор тега TypeScript
    Тлен
    Ответ на твой вопрос на самом деле зависит от того, что за говно у тебя в cartEmptyImg.
    Т.к. голый js не умеет в принципе импортировать что-то кроме js модулей - это полностью зависит от твоей конфигурации загрузчиков и настроек, о которых в вопросе не сказано ни слова.
    Даже хотя-бы полный текст ошибки частично пролил бы свет на этот вопрос, но конечно же "лишняя" информация в вопросе не нужна, да.

    В целом тут может быть несколько вариантов:
    1. Используется простой загрузчик, который в импорт подставит простой url или data uri, тогда у тебя хреново настроен тип для png: должен быть где-то файлик условно вида:
    png.d.ts
    declare module '*.png' {
      const png: string;
      export default png;
    }

    2. Используется какая-то более продвинутая хрень(генератор спрайтов, генератор react-копонентов, и т.д.). Тут уж сам смотри что там и куда это что-то надо пихать, потому как без инфы тут можно только гадать на кофейной гуще.
    Ответ написан
  • Как конкретизировать сложный тип?

    Aetae
    @Aetae Автор вопроса, куратор тега TypeScript
    Тлен
    И вот в ts 4.9 наконец-то ввели фичу отвечающую на этот вопрос (буквально джва года ждал):
    interface Some {
      value: string | string[];
    }
    
    const foo = {
      value: ['a', 'b'] // здесь всегда будет массив
    } satisfies Some;
    
    foo.value.map(() => {}); // ок
    Ответ написан
    Комментировать
  • Как правильно типизировать аругменты?

    Aetae
    @Aetae Куратор тега TypeScript
    Тлен
    const someFunc = <
      FK extends keyof FormDataType, 
      SK extends keyof FormDataType[FK]
    >(
    	firstKey: FK, 
    	secondKey: SK
    ) => {
      ...
    }
    Ответ написан
    Комментировать
  • Как подсветить все ошибки typescript в webstorm?

    Aetae
    @Aetae Куратор тега TypeScript
    Тлен
    На самом деле твой вопрос: "Как подсветить ошибки типов typescript внутри шаблонов vue в webstorm".

    Ответ: никак.

    Они завязали всё на стороннюю тулзу и плагин к vscode, а не на языковой сервис typescript, потому любые ide кроме vscode в пролёте. Это очень расстраивает, да.

    У меня есть личные намётки на эту тему, но оно движется медленно и постоянно откладывается, т.к. есть задачи по-актуальней, так что в ближайшее время можно не ждать.)

    P.S. Могу пока порекомендовать плагин awesome console - он сделает кликабеьными все ссылки в консоли, включая переход к конкретной строчке.
    Ответ написан
    1 комментарий
  • Как указать компилятору скопировать .json схемы?

    Aetae
    @Aetae Куратор тега TypeScript
    Тлен
    Если ты не используешь никаких систем сборки, а только чистый tsc - то оный отвечает только и исключительно за транспиляцию самого ts, всё остальное тебе придётся делать тупо ручками: написать bash\bat\nodejs скрипт, который последовательно запустит tsc, потом запустит твой "пакет", затем просто скопирует нужные файлы в папочку dist.

    Если используешь - гугли соответствующие плагины для конкретной системы, либо пиши свои(это проще чем кажется). Например для webpack есть copy-webpack-plugin.
    Ответ написан
    1 комментарий
  • Как типизировать в ts?

    Aetae
    @Aetae Куратор тега TypeScript
    Тлен
    Вопрос конечно в духе "я его того, а он мне нихрна, чаво это он". Где конкретика блин? Что именно за ошибка? Любая ошибка TS - это "ошибка типов", он для этого и существует. Что у тебя в route?

    Но окей, предположим, что route у тебя - это текущий роут vue-рутера, тогда ошибка у тебя скорее всего выглядит как-то так:
    TS7053: Element implicitly has an 'any' type because expression of type 'RouteRecordName' can't be used to index type '{ first: string; second: string; }'.   No index signature with a parameter of type 'string' was found on type '{ first: string; second: string; }'.

    Собственно прочитав текст ошибки можно уже догадаться, в чём проблема: у (неявно выведенного за отсутствием явного объявления) типа объекта pages есть ключи типа 'first' | 'second' | ..., но нет index signature типа string, т.е. не указано, что ключом может быть любая строка, а не только конкретные'first' | 'second' | ....
    route.name же после проверки на пустоту имеет тип string | symbol. Ты не можешь у объекта с чётко ограниченным набором ключей брать значение по произвольному строковому/символьному.

    Прямое решение в лоб:
    Задать тип pages позволяющий рандомные ключи, например
    const pages: Record<PropertyKey, string> = {
      first: 'Первая',
      second: 'Вторая',
      ...
    }

    Всё сразу заработает, но это не спасёт тебя от ошибок(например опечаток).


    Не менее прямой вариант
    (но с другой стороны):
    Кастануть нужный тип руками: ... = pages[route.name as keyof typeof pages]
    Ведь мы уверены, что name в route всегда будет одним из ключей pages. Уверены же?..

    Энтерпрайз решение(ничем не лучше предыдущих, зато выглядит солидно):
    Твой файл routes.ts:
    export enum ERoutes {
      FIRST = 'first',
      SECOND = 'second'
    }
    
    const routes = [
      {
         name: ERoutes.FIRST,
         ...
      },
      {
         name: ERoutes.SECOND,
         ...
      },
      ...
    ]

    В коде:
    const pages: Record<ERoutes, string> = {
      [ERoutes.FIRST]: 'Первая',
      [ERoutes.SECOND]: 'Вторая',
      ...
    }
    
    ... = pages[route.name as ERoutes]


    Надмозговое решение("как батька"):
    Твой файл routes.ts:
    const routes = [
      {
         name: 'first',
         ...
      },
      {
         name: 'second',
         ...
      },
      ...
    ] as const satisfies ReadonlyArray<ReadonlyRouteRecordRaw>;
    
    type ReadonlyRouteRecordRaw = Omit<RouteRecordRaw, 'children'> & {
      children?: ReadonlyArray<ReadonlyRouteRecordRaw>;
    };
    
    type ExtractNames<Route> = Route extends { name: infer Name } ? Name : never;
    type FlattenChildren<Route> = Route extends { children: ReadonlyArray<infer Children> }
      ? FlattenChildren<Children> | Route
      : Route;
    
    // с помощью магии ts вытаскиваем в тип RouteNames все заданные у нас имена маршрутов
    export type RouteNames = ExtractNames<FlattenChildren<typeof routes[number]>>;
    
    // с помощью магии же прокидывем их прямо в декларацию vue-router
    declare module 'vue-router' {
      export interface RouteLocationNormalizedLoaded {
        name: RouteNames | null | undefined;
      }
    }

    satisfies
    satisfies - новая фича ts 4.9, в предыдущих версиях того же можно добиться сделав обёртку вида:
    const narrowRoutesTypeWrapper = <T extends ReadonlyArray<ReadonlyRouteRecordRaw>>(routes: T) => routes;
    const routes = narrowRoutesTypeWrapper([ ... ] as const);

    И твой код заработает вообще без изменений (если в pages есть все нужные ключи).)
    Однако для удобства можно написать так:
    const pages: Record<RouteNames, string> = {
      first: 'Первая',
      second: 'Вторая',
      ...
    }
    Ответ написан
    Комментировать
  • Как компилировать ts в js используя cdn?

    Aetae
    @Aetae Куратор тега TypeScript
    Тлен
    Есть какая-то такая хрень:
    https://www.npmjs.com/package/ts-browser-klesun
    https://www.npmjs.com/package/ts-browser

    Но правильный ответ: на проде - никак. Компиляция ts это жирнющий процесс, который будет работать очень медленно.
    Ответ написан
    Комментировать
  • Для чего нужен параметр sourceMap в tsconfig?

    Aetae
    @Aetae Куратор тега TypeScript
    Тлен
    webpack - это webpack, typescript - это typescript, всекаешь?

    Если нет, то поясню: это разные инструменты, которые могут прекрасно работать сами по себе и никак не пересекаться. Но в обоих случаях есть необходимость sourceMap.
    Если говорить о связке webpack и typescript, при работе в лоб webpack, как сборщик, потребляет sourceMap из typescript и генерирует из них свои.

    Сгенерированные из webpack sourceMap при отключении оных в typescript могут иметь разный вид в зависимости от настроек, плагинов и режимов: от нормальных, т.к. об этом позаботились плагины или вообще компиляция шла через babel, до полностью сломанных и бесполезных.
    Ответ написан
    Комментировать