Задать вопрос
Ответы пользователя по тегу TypeScript
  • Почему typescript не проверяет типы при использовании spread-оператора?

    Aetae
    @Aetae Куратор тега TypeScript
    Тлен
    Потому что необходимое свойство value уже существует, а остальной мусор пофиг, т.к. в ts структурная типизация, т.е. под сигнатуру
    interface Props {
        readonly value: string;
    }
    подходит любой объект у которого есть value: string:
    const foo = {
        value: 'string',
        id: 'string'
    }
    const bar: Props = foo; // ok

    Как указал Alexandroppolus - проверка есть только при явном задании литерала:
    const bar: Props = {
        value: 'string',
        id: 'string' // err
    };
    Но это специальный случай - предполагается, что задавая литерал вы хотите задать именно объект указанного типа и никакой другого. Однако к парадигме структурной типизации используемой в ts это отношения не имеет, чисто quality of life фича.

    P.S. И да, это значит что в потенциале ты можешь сделать так:
    interface Props {
        readonly value: string;
    }
    interface Props2 {
        readonly value: string;
        readonly id?: number;
    }
    
    const foo = {
        value: 'string',
        id: 'string'
    }
    
    const bar: Props = foo; 
    const buz: Props2 = bar; 
    
    buz.id?.toFixed(2) // ts ok, runtime error :(
    Ответ написан
    Комментировать
  • Зависает на запросах после сборки через webpack?

    Aetae
    @Aetae Куратор тега JavaScript
    Тлен
    Возможно дело в том что не вынесены node модули как внешние:
    const nodeExternals = require('webpack-node-externals');
    {
      // ...
      externals: [nodeExternals()],
    }


    Если это не поможжет, то отключи все плагины и оптимизацию.
    Не заработало?
    Сделай тестовый файлик с одним единственным методом, собери и посмотри на результирующий код - подебаж его руками и разберись в чём дело.

    Работает?
    Подключай плагины по одному пока не найдёшь виновника и разбирайся с конфигом оного.
    Ответ написан
  • Как сделать типизацию под случай undefined в объекте?

    Aetae
    @Aetae Куратор тега TypeScript
    Тлен
    Никак. Тип undefined не может быть ключом в принципе.
    Из вариантов:
    1. Убедиться что ключ не undefined руками:
    card = card_id && this.cards[card_id];
    2. Заставить ts думать, что ключ есть даже если его нет(и взять на себя ответственность за возможные ошибки):
    card = this.cards[card_id!];
    3. Явно привести к строке:
    card = this.cards[String(card_id)];
    Ответ написан
    5 комментариев
  • Как использовать объект VNodeRef?

    Aetae
    @Aetae Куратор тега TypeScript
    Тлен
    Зачем ты огород то городишь?
    :ref="setPostRef"
    -->
    ref="postRefs"

    И всё, в postRefs.value у тебя массив элементов.

    В твоём варианте ты прям в кишки vue лезешь.
    Ответ написан
    Комментировать
  • Как убрать "Property does not exist on type" в рекурсивном интерфейсе?

    Aetae
    @Aetae Куратор тега TypeScript
    Тлен
    На каждом уровне проверять, что значение не string и не number. Иначе никак, ты сам задал такой тип, и ts не даст тебе совершить ошибку.

    Если у тебя только 2 уровня, то не надо рекурсии:
    interface CSS {
        [k: string]: {
            [k: string]: string | number 
        }
    }


    Если ты хочешь сузить тип при создании констатны, можно сделать так:
    const css = {
        default: {
            color: '#676767',
            border: '1px solid',
            border_color: '#C4C4C4',
            border_radius: '110px',
    
            padding: '16px 21px',
        }
    } satisfies CSS;
    Ответ написан
    Комментировать
  • Почему не работают алиасы?

    Aetae
    @Aetae Куратор тега TypeScript
    Тлен
    paths в tsconfig - это чисто справочная информация для подсветки, добавленная из расчёта, что вы уже используете какой-то сборщик который такие пути умеет.
    Сам по себе он влияет точно и исключительно на подсветку, нужны сторонние сборщики и\или модули.
    Это by design и wont fix.

    Предполагаемое разработчиками решение: взять какой-ниь vite или webpack и настроить там руками точно такие же алиасы.
    Популярный костыль, который сделает это за тебя для любых вариантов, в том числе и ts-node: tsconfig-paths
    Ответ написан
    Комментировать
  • Как для возвращаемого типа функции задать типы входных параметров Function[]?

    Aetae
    @Aetae Куратор тега TypeScript
    Тлен
    Как-то так, если по красоте:
    type Returns<T extends readonly Function[]> = {
      -readonly [K in keyof T]: T[K] extends (...args: any[]) => PromiseLike<infer R> ? R : never;
    };
    
    type Arguments<T extends readonly Function[]> = {
      [K in keyof T]?: T[K] extends (args: infer R, ...a: any[]) => any ? R : never;
    };
    
    function fetchAll<T extends readonly Function[]>(functions: readonly [...T], data?: Arguments<T>): Promise<Returns<T>> {
      return Promise.all(
        functions.map((func, index) => func(data?.[index]))
      ) as Promise<Returns<T>>;
    }
    
    const x = fetchAll([
      (a:66) => Promise.resolve(42),
      (f:string) => Promise.resolve('hello'),
      () => Promise.resolve(true),
    ], [66, '1ff']);


    Если надо отельный массив, то придётся его руками const:
    const arr = [
      (a:66) => Promise.resolve(42),
      (f:string) => Promise.resolve('hello'),
      () => Promise.resolve(true),
    ] as const;
    
    const x = fetchAll(arr, [66, '1ff']);
    Ответ написан
    4 комментария
  • Почему не собирается проект из за PrismaAdapter?

    Aetae
    @Aetae Куратор тега TypeScript
    Тлен
    Ошибка возникает не у тебя, а в стороннем коде модуля next-auth.
    Заигнорить это можно указав skipLibCheck в tsconfig.
    Однако лучше, по возможности, разобраться: причиной может быть что ты используешь слишком старую версию typecript, или старую версию модуля, или случайно подключаешь несколько версий модуля одновременно, или ещё много куда менее вероятных вариантов.
    Ответ написан
  • Почему не получается задать либо один тип либо другой в typescript?

    Aetae
    @Aetae Куратор тега TypeScript
    Тлен
    В action ты кладёшь функцию onClick с сигнатурой (item: LinkItem) => void, а требуется (data: MobileMegaMenuItem | LinkItem) => void, , т.е. функция которая умеет работать и с тем и с тем. Подразумевается что onClick как раз не умеет и может привести к ошибке, потому и не даёт.

    Используй дженерик чтобы вывести конкретный тип:
    export const useOpenMenuByHash = <Data extends MobileMegaMenuItem | LinkItem>(
        data: Data[],
        action: (data: Data) => void,
        actionRoom?: () => void
    ) => {
      //...
    };
    
    useOpenMenuByHash(data, onClick); // ok

    Ну или кастуй руками:
    useOpenMenuByHash(data, onClick as (d: LinkItem | MobileMegaMenuItem) => void);
    Ответ написан
    4 комментария
  • Можно ли передать нужный тип переменной в дженерик функции?

    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)
    Ответ написан
    Комментировать