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

    Aetae
    @Aetae Куратор тега TypeScript
    Тлен
    getFormattedData тоже должен быть дженерик и собсно его(дженерик) прокидывать в нижестоящие.

    Типа того:
    type Type1 = 1;
    type Type2 = 2;
    type Type3 = 3;
     
    type ContainsType<T extends UniversalType = UniversalType> = {type: T};
    
    type UniversalType = Type1 | Type2 | Type3;
    
    
    class Cls {
      async getFormattedData<T extends UniversalType>(data: ContainsType<T>): Promise<T> {
            const anyDataObject = this.validateData(data);
            const result = this.formatDataByType(anyDataObject);
            return result;
      }
    
      validateData<T extends UniversalType = UniversalType>(data: ContainsType<T>): T {
        return data.type
      }
    
      formatDataByType<T extends UniversalType = UniversalType>(data: T): T {
        return data
      }
    
    }
    const foo = await new Cls().getFormattedData({type: 2}); // 2


    Если ты явно чему-то пропиваешь тип который никак не зависит от входного дженерика:
    const anyDataObject: Type1 | Type2 | Type3 = ...
    то какбэ всё - приехали, ты сам указал, что тут именно такой тип(во всём его многообразии) и пофиг на входные данные. Ты можешь дальше сузить тип внутри метода:
    if (anyDataObject === 2) {
      // тут anyDataObject для ts считается Type2
    }
    но это уже никак не повлияет на выходной тип.

    В общем выводить типы можно только если они зависят от входных данных(которые в свою очередь получаются через дженерик), иначе откуда TS узнает, что там от чего зависит.
    Если ты заранее даже приблизительно не знаешь, что придёт на вход, то и что пойдёт на выход ты ноже не знаешь, а не знаешь ты - не знает и, тем более, TS: там просто одни произвольные данные превратились в другие без использования логики. С тем же успехом можно попытаться вывести точный тип Math.random().
    Ответ написан
    Комментировать
  • Как расширить дженерик MutableRefObject добавив в него новое свойство?

    Aetae
    @Aetae Куратор тега TypeScript
    Тлен
    Ну какбэ очевидно, что:
    interface MutableRefObject<T> {
      prev: null | HTMLParagraphElement; 
    }


    Если интeрфейс в либе, то:
    declare module 'lib-name' {
      interface MutableRefObject<T> {
        prev: null | HTMLParagraphElement; 
      }
    }

    Или, хуже:
    declare module 'lib-name/full/path/to/declaration.ts' {
      interface MutableRefObject<T> {
        prev: null | HTMLParagraphElement; 
      }
    }


    Но вообще, если для себя то делай так:
    interface MySuperMutableRefObject extends MutableRefObject<T> {
      prev?: null | HTMLParagraphElement; 
    }

    и не трогай библиотечный тип.
    Ответ написан
    6 комментариев
  • Как использовать один компонент с разными типами данных?

    Aetae
    @Aetae Куратор тега TypeScript
    Тлен
    Наверное ты хочешь этого:
    type Props = { data?: ITemplate } | {}
    const CreateTemplateForm: FC<Props> = (props) => {
      if ('data' in props && props.data) {
        
        return ...;
      }
    
      return ...;
    }
    Ответ написан
    5 комментариев
  • Почему TS не компилирует пути для JS?

    Aetae
    @Aetae Куратор тега TypeScript
    Тлен
    paths в tsconfig работают только визуально. Чтобы они работали физически - надо продублирвать их в алиасы того сборщика, который вы используете.
    paths - не первичны, а вторичны: они сделаны как отражение возможностей алиасов в сборщиков, а не как самостоятельная фича.
    Ответ написан
    1 комментарий
  • Почему при сборке библиотеки и подключения ее, выдает ошибку?

    Aetae
    @Aetae Куратор тега TypeScript
    Тлен
    Не надо ничего "копировать из dist". В node_modules должен быть модуль, т.е. в первую очередь файлик package.json, во вторую - всё что в нём указано по тем путям которые там указаны.
    Вот когда ты делаешь npm link - открой node_modules и посмотри как должна выглядеть твоя либа(только без исходников).
    Когда ты сделаешь нормальный npm publish - токчно также всё просто скопируется в npm.
    Ответ написан
    Комментировать
  • TypeScript: как убрать null из свойства объекта?

    Aetae
    @Aetae Куратор тега TypeScript
    Тлен
    if (error.value?.statusCode !== 404) не гарантирует, что в user не будет null, мало ли там ошибка 50х или даже нет ошибки, а просто сервер глюканул.

    Так что у тебя два варианта:
    1. То что от тебя хочет typescript, явная проверка:
    if (!user) {
      throw new Error('empty responce')
    }

    2. Исправление типа, если ты очень доверяешь своему серверу:
    а) Вариант предложенный Lynn «Кофеман» с явным кастом;
    б) Обёртка над useFetch которая внутри себя скастует тип по новому или изменение самого типа useFetch.
    Ответ написан
    Комментировать
  • Как типизировать вложенного объекта в объекте в одну строку?

    Aetae
    @Aetae Куратор тега TypeScript
    Тлен
    Тупо скастовать можно так:
    const result = (blogPosts as Posts)[props.name]

    Но это не правильно, по хорошему ты должен изначально убедиться, что blogPosts - нужного типа:
    // тайпргард: тут проверка что posts действительно Posts; 
    const isPosts = (posts: unknown): posts is Posts => !!posts 
      && typeof posts === 'object' 
    //&& ... ;
    
    if (!isPosts(blogPosts)) throw new Error('wrong blogPosts');
    
    const result = blogPosts[props.name];
    Ответ написан
    4 комментария
  • Как правильно ограничивать передаваемые аргументы классов в TypeScript?

    Aetae
    @Aetae Куратор тега TypeScript
    Тлен
    1. TypeScript работает на этапе компиляции. В рантайме нет никакого тайпскрипта, соответственно и не может быть никаких проверок с ним связанных.
    // Есть библиотеки для подобного, но они сильно жирные и слегка "хакнутые", в простых случаях лучше уж руками

    2. TypeScript имеет структурную типизацию. Что значит, что учитвает он только структуру. Тип получаемый из пустого абстрактного класса будет принимать в себя абсолютно любой объект. Тип из класса с одним полем "id" примет в себя любой инстанс любого класса с полем "id".
    class A { id!: string }
    class B { id!: string }
    class C { 
     id!: string; 
     value!: number; 
    }
    
    const foo: A = new B(); // ok
    const bar: A = new C(); // still ok

    3. Неизвестный тип в TypeScript обозначается unknown. Функции проверки что неизвестный тип является конкретным называются тайпгарды:
    function isString(arg: unknown): arg is string {
      return typeof arg === 'syting'
    }

    Применяя тайпгарды вы полностью берёте на себя ответственность, что поверки истинны.
    Ответ написан
  • Почему у пересечения функций такой ReturnType?

    Aetae
    @Aetae Куратор тега TypeScript
    Тлен
    Ни в чём. Просто ограничение языка. Видимо слишком сложно было сделать и\или обосновать. Возможно в какой-то следующей версии языка пофиксят.

    Вот issue помеченная как "Design Limitation", там есть workaroud(который не стоит юзать в проде, разве что если очень хочется).
    Ответ написан
    5 комментариев
  • Как исправить ошибку с типизацией при передаче аргумента?

    Aetae
    @Aetae Куратор тега TypeScript
    Тлен
    М.б. так
    @click="data && handleUpdate(data.id, data.status)"
    , но вообще лучше заранее убедиться, что data есть, а не злоупотреблять ?..

    Ну и конечно, если handleUpdate'у на самом деле пофиг на значения, то можно и так:
    const handleUpdate = async (id?: number, status?: statusType)
    Ответ написан
    Комментировать
  • Как правильно типизировать переменную?

    Aetae
    @Aetae Куратор тега TypeScript
    Тлен
    Поменяй: props.item.office на 'office' in props.item.
    Ты не можешь обращаться к свойству которого нет сразу во всех типах union'a. Но ты можешь проверить его наличие, а дальше ts, в зависимости от результата, сузит тип до того, в котором оно присутствует.
    Ответ написан
    Комментировать
  • Проблема с React children?

    Aetae
    @Aetae Куратор тега TypeScript
    Тлен
    Делая так:
    const ThemeProvider: FC = ...;
    Ты говоришь ts, что у тебя ThemeProvider имеет тип FC, и пофиг что ты там дальше пишешь. Тип FC по умолчанию не имеет children.

    Пиши либо так:
    const ThemeProvider: FC<{children: ...}> = ...;

    Либо так:
    const ThemeProvider = ({ children }: ...) => ...;
    * Кстати обрати внимание на деструктуризацию, в react component всегда приходят props, children это поле props, а не верхний аргумент.

    Либо так:
    const ThemeProvider: FC<PropsWithChildren> = ...
    * PropsWithChildren - тип помощник, добавляющий children к объекту, например
    PropsWithChildren<{
     prop2: string; 
     prop3: number
    }>
    но без дженерика просто отдаёт тип вида
    {
        children?: ReactNode | undefined;
    }
    Ответ написан
  • Как типизировать числа с точкой и тире?

    Aetae
    @Aetae Куратор тега TypeScript
    Тлен
    В принципе ts позволяет при желании извратиться и побуквенно наклепать нужные типы:
    type Lettrer = 'a' | 'b' | ...
    type Digit = 1 | 2 | ...
    ...

    Но делать так, очевидно, не стоит. :)
    Оставьте просто string и просто number.
    Разве что для удобства чтения и понимания (а также как задел на случай если ts поумнеет в будущем и сможет в более сложные типы) сделайте так:
    type ZipCode = string;
    type GeoCoord = number;
    Ответ написан
  • Как исправить ошибку Module not found с версией react-scripts 5?

    Aetae
    @Aetae Куратор тега TypeScript
    Тлен
    compilerOptions.path влияет только собсно на "красные подчёркивания", tsconfig никак не управляет настоящими путями.
    Тебе надо руками прописывать alias в конфиге webpack.
    Ответ написан
    6 комментариев
  • Как типизировать функцию в vitest, что бы можно было вызвать у нее метод mockReturnValue?

    Aetae
    @Aetae Куратор тега TypeScript
    Тлен
    const useScreenResolution: Mock & ((<args type>) => <return type>) = (...) => {...}
    ?
    Ответ написан
  • Как исправить ошибку "Property *** does not exists on type ''IntrinsicAttributes" в React+TypeScript?

    Aetae
    @Aetae Куратор тега JavaScript
    Тлен
    Тебе английским по белому написано: "Property todos does not exists", что тут непонятно?

    Твой компонент TodoList не ожидает пропа todos.
    Ответ написан
    Комментировать
  • Как решить ошибку TS в атрибуте name для input type = radio?

    Aetae
    @Aetae Куратор тега TypeScript
    Тлен
    Ну name ждёт стрингу и не ждёт намбер, что тут непонятного?)
    "Правильно" - сделать как-то так :name="`${modelValue}`", но я бы попатчил типы инпута ибо он сам себе всё прекрасно преобразует.
    Ответ написан
    Комментировать
  • Правильное описание типов для колонок таблицы (Typescript)?

    Aetae
    @Aetae Куратор тега TypeScript
    Тлен
    Чтоюы union объектов работал - у него должно быть поле-дискриминатор(поле которое есть в каждом объекте и отличает его от другого), допустим type:
    type BaseColumn = { label: string; props: string }
    
    type Column = { type: 'text' } & BaseColumn
    
    type LinkColumn = { type: 'link'; path: string } & BaseColumn
    
    type TableColumn = Column | LinkColumn


    keyof для юниона объектов показывает только те поля, которые есть в каждом из них. Это логично, т.к. к типу TableColumn ты не можешь обратиться по полую .link предварительно не сузив тип. union - строгий.
    Ответ написан
    Комментировать
  • Почему не работает локальная библеотека на сборке Vite?

    Aetae
    @Aetae Куратор тега TypeScript
    Тлен
    declare module "custom-editor"
    import Editor from 'custom-editor-lib/dist/index'

    Не замечаешь разницы?
    Ответ написан
    Комментировать
  • Как типизировать router.push(pathname)?

    Aetae
    @Aetae Куратор тега TypeScript
    Тлен
    Проверил чистую установку next 13.4.12 - такой проблемы нет.

    Где-то говняет типы роутера. Возможно у тебя отдельно в package.json подключена устаревшая в версия роутера - тогда удали её.
    Иначе тыкни Ctrl+Click на .push и тебе откроет файл с декларацией, если она не\не только в next/dist/shared/lib/app-router-context.d.ts - разбирайся откуда взялась левая.
    Ответ написан
    Комментировать