Ответы пользователя по тегу TypeScript
  • Как правильно типизировать функцию?

    bingo347
    @bingo347 Куратор тега TypeScript
    Crazy on performance...
    function preparedData<T extends Record<string, {name: string, id: string}[]>>(data: T) {
      return Object.keys(data).map((key) => {
        return data[key as keyof T].map((a) => ({
          val: a.name,
          newId: a.id,
        }));
      });
    }

    https://www.typescriptlang.org/play?#code/GYVwdgxg...
    Ответ написан
    Комментировать
  • Типы сигнатур функций в TypeScript это почти как делегаты в C#?

    bingo347
    @bingo347 Куратор тега TypeScript
    Crazy on performance...
    Функциональные типы в TS - это типы, значением которых может являться любая функция с совместимой сигнатурой. Методы классов - это те же функции. При этом надо помнить, что this в JS/TS определяется вызовом, а не объявлением функции/метода.
    И это существенно отличает их от делегатов в шарпе, которые по своей сути являются умной ссылкой на метод конкретного инстанса.

    Аналог делегата из шарпа на TS может выглядеть как то так:
    class Delegate<Target, Args extends any[], Ret> {
        constructor(
            private target: Target,
            private method: (this: Target, ...args: Args) => Ret,
        ) {}
    
        public invoke(...args: Args): Ret {
            return this.method.apply(this.target, args);
        }
    }
    Вот только конструировать такой делегат в отличии от шарпа придется явно.

    https://www.typescriptlang.org/play?#code/MYGwhgzh...
    Ответ написан
    Комментировать
  • Почему в интерфейс не записывается тип boolean?

    bingo347
    @bingo347 Куратор тега TypeScript
    Crazy on performance...
    В TypeScript есть литеральные типы ('some string', 1, 2, 3, true, false).
    Значение константы поменять нельзя, поэтому TypeScript выводит для них литеральный тип.
    Поэтому тип q будет не boolean, а true.
    Ответ написан
    4 комментария
  • Почему происходит ошибка типизации computed сomposition api во vue 3?

    bingo347
    @bingo347 Куратор тега TypeScript
    Crazy on performance...
    А что Вам не понятно в описании текста ошибки?
    Argument of type 'ComputedRef' is not assignable to parameter of type 'string'.

    Давайте я засуну в переводчик за Вас:
    Аргумент типа 'ComputedRef' не может быть присвоен параметру типа 'string'.


    const pErrorMinMessage = computed<string>(() => {
      return 'world'
    })
    const fun1 = function (val: string) {
      console.log('hello' + val)
    }
    
    fun1(pErrorMinMessage.value)
    Ответ написан
    1 комментарий
  • Как типизировать useReducer и есть ли в целом более аккуратные варианты?

    bingo347
    @bingo347 Куратор тега TypeScript
    Crazy on performance...
    type AlbumType = {
      id: number;
      title: string;
    };
    
    enum ActionPoints {
      SET_ALBUMS = "SET_ALBUMS",
      ADD_ALBUM = "ADD_ALBUM",
      REMOVE_ALBUM = "REMOVE_ALBUM"
    }
    
    type ActionType = {
      type: ActionPoints.SET_ALBUMS;
      payload: AlbumType[];
    } | {
      type: ActionPoints.ADD_ALBUM;
      payload: AlbumType;
    } | {
      type: ActionPoints.REMOVE_ALBUM;
      payload: number;
    };
    
    const reducer = (state: AlbumType[], action: ActionType) => {
      switch (action.type) {
        case ActionPoints.SET_ALBUMS:
          return action.payload;
        case ActionPoints.ADD_ALBUM:
          return [...state, action.payload];
        case ActionPoints.REMOVE_ALBUM:
          return state.filter((album) => album.id !== action.payload);
        default:
          return state;
      }
    };
    Ответ написан
    1 комментарий
  • Нужен ли babel, если используешь TypeScript?

    bingo347
    @bingo347 Куратор тега TypeScript
    Crazy on performance...
    Typescript compiler - это инструмент проверки типов и компиляции typescript в javascript. Так же он умеет транспайлить конструкции новых стандартов js в более старые стандарты, но это не основная задача этого инструмента, и делает он это хуже целевых инструментов, в частности его можно настроить только на конкретный стандарт.

    Babel - это инструмент для парсинга js кода в AST, обхода и модификации AST и обратной сериализации AST в js. Так же это еще и экосистема плагинов и пресетов. Плагины как правило реализуют транспиляцию одной из фич более нового стандарта в более старый. Пресеты - это просто конфигурируемый набор плагинов.
    Так же в Babel AST есть поддержка некоторых расширений js (а ts - это тоже расширение js), но включается это все флагами.

    В экосистеме babel есть preset-env нацеленный именно на транспиляцию более новых стандартов в более старые. Его особенностью является поддержка browserlist и подключения только тех плагинов, которые нужны для указанных браузеров. За счет этого получается более оптимальный js на выходе, так как многие фичи после транспайлинга работают медленнее чем нативные и занимают больше кода.

    Еще в экосистеме babel есть preset-typescript, который включает поддержку ts синтаксиса и транспиляцию ts в js. При этом, в отличии от tsc, он не делает проверку типов, а некоторые сущности может обрабатывать неправильно (как и большинство сторонних компиляторов ts, т.к. у ts нет строгой спеки и единственным источником правды является код tsc, который далек от идеального).

    Оптимальным по выходному результату (пусть и за счет времени сборки) будет вариант, когда сначала ts код обрабатывается через tsc без транспиляции в старые стандарты, а затем происходит транспиляция с помощью babel + preset-env + browserlist.
    Ответ написан
    1 комментарий
  • Как указать типы данных в импортируемом json файле?

    bingo347
    @bingo347 Куратор тега Node.js
    Crazy on performance...
    https://www.typescriptlang.org/tsconfig#resolveJso...

    Ну или создайте рядом с db.json файл db.json.d.ts со следующим содержимым:
    declare const JSON: {
        id: number;
    }[];
    export default JSON;
    Ответ написан
    Комментировать
  • Как задать тип рекурсивно?

    bingo347
    @bingo347 Куратор тега TypeScript
    Crazy on performance...
    interface Props {
      list: {
        id: number;
        name: string;
        children?: Props['list'];
      }[];
    }

    или
    interface PropsListItem {
      id: number;
      name: string;
      children?: PropsListItem[];
    }
    
    interface Props {
      list: PropsListItem[];
    }
    Ответ написан
    Комментировать
  • Как задать тип для массива из объектов?

    bingo347
    @bingo347 Куратор тега TypeScript
    Crazy on performance...
    type T = {
      id: number;
      quantity: number;
    }[];
    Ответ написан
    Комментировать
  • Как из строковых литералов сделать тип массива?

    bingo347
    @bingo347 Куратор тега JavaScript
    Crazy on performance...
    В TS есть 2 варианта итерироваться по частям юнион типа - это условные типы и итерация по ключам, притом итерация по ключам ограничена типом number | string | symbol

    Условные типы проверяют условие для каждого варианта юниона, а значит позволяют трансформировать каждый из вариантов по отдельности:
    type MyFunc = <N extends string>() => (N extends string ? Field<N> : never)[];
    но возвращаемый тип так же будет юнионом:({ name: "town" } | { name: "city" })[]

    Сделать кортежный тип из юниона не выйдет, так как в юнионе не определен порядок, тип "town" | "city" это тоже самое, что и тип "city" | "town".
    Но можно сделать кортеж из кортежа:
    type MyFunc = <N extends string[]>() => {
        [K in keyof N]: N[K] extends string ? Field<N[K]> : never;
    };
    
    myFunc<["town", "city"]>()


    Ну и в реальном коде гораздо удобнее, когда дженерик выводится из аргументов, а для того что бы TS сам вывел кортежный тип из абстрактного массива, данный массив нужно помечать as const, что так же делает его readonly массивом. Но принимать аргументы через readonly там где нам не нужно их мутирорвать - это вообще хорошая практика. Полный пример будет выглядеть так:
    https://www.typescriptlang.org/play?#code/C4TwDgpg...
    Ответ написан
    Комментировать
  • Как реализуется enum в JS из Typescript?

    bingo347
    @bingo347 Куратор тега JavaScript
    Crazy on performance...
    Можете, пожалуйста, объяснить, что выполняет эта часть кода: (Membership || (Membership = {})
    Если в Membership не falsy значение (например объект), то передать ссылку на него в функцию, иначе (если в Membership undefined) присвоить в Membership новый объект и передать ссылку на него в функцию

    И почему это всё обёрнуто в функцию?
    Сложно сказать, думаю кто-то скопировал код отсюда в код сюда и не стал париться, так как в обоих случаях есть declaration merging, о котором уже написал Aetae

    А вообще стоит узнать про const enum, который не оставляет артефактов в JS и в подавляющем большинстве случаев его достаточно.
    Ответ написан
    Комментировать
  • Как получить список полей из интерфейса?

    bingo347
    @bingo347 Куратор тега TypeScript
    Crazy on performance...
    const credTester: Record<keyof Credentials, RegExp> = {
            login: /^[0-9a-zA-Z]*$/,
            password: /^[0-9a-zA-Z@#.]*$/
    };
    Ответ написан
    Комментировать
  • В чем ошибка с типами User?

    bingo347
    @bingo347 Куратор тега TypeScript
    Crazy on performance...
    useState<User[] | null>(null);
    Здесь Вы пишите, что в стейте у Вас либо null либо массив юзеров.
    const _user = (await response.json()) as User;
    setItem(_user);
    а здесь Вы уговорили TS что ответ - это 1 юзер и пытаетесь передать его в стейт.

    interface IUserInfoProps {
      user: User;
    }
    а вот здесь у Вас компонент так же принимает только одного юзера, но передаете Вы ему
    <UserInfo user={item} />
    значение из стейта с типом User[] | null
    Ответ написан
  • Как использовать миксины на асбтрактные классы?

    bingo347
    @bingo347 Куратор тега TypeScript
    Crazy on performance...
    Generic type 'Constructor2' requires 1 type argument(s).

    У Вас тип Constructor2 требует дженерик аргумента, а вот тут Вы его используете без дженерика:function Activatable<TBase extends Constructor2>
    Можно попробовать так:
    function Activatable<T, TBase extends Constructor2<T>>
    хотя это сильно зависит от задачи...

    Type 'TBase' is not a constructor function type.
    эта ошибка вылезла из предыдущей

    Cannot create an instance of an abstract class.

    Cannot assign an abstract constructor type to a non-abstract constructor type
    все правильно ругается, абстрактные классы на то и абстрактные, что в них есть абстрактные методы, у которых реализация должна быть в наследнике, их конструирование приведет к ошибкам и TS от этого защищает.

    A mixin class that extends from a type variable containing an abstract construct signature must also be declared 'abstract'.
    Миксин принимает на вход произвольный абстрактный класс, не зная о всех его абстрактных методах, поэтому он тоже должен быть абстрактным.

    type AbstractConstructor<T> = Function & { prototype: T };
    Вот этот тип некорректен...
    Ответ написан
    Комментировать
  • Как исправить ошибку Vue + TypeScript?

    bingo347
    @bingo347 Куратор тега TypeScript
    Crazy on performance...
    А что Вам не понятно из описания ошибки?
    Вы пытаетесь присвоить объект ComputedRef<number>, возвращаемый функцией computed в поле объекта объявленное как number.
    Нужно или поменять тип у поля, или обновлять поле через watch.
    Ответ написан
    5 комментариев
  • Что означает данное ниже определение в Typescript?

    bingo347
    @bingo347 Куратор тега TypeScript
    Crazy on performance...
    Тип Record - это утилити тип из стандартной библиотеки TS, который описывает объект, у которого ключи - первый аргумент дженерика, а значения - второй.
    Тип string[] | Record<string, any>[] - это или массив строк или массив объектов (ключ - любая строка, значение любого типа). Данный тип не позволит смешивать строки и объекты в одном массиве, либо то либо другое.
    Как верно подметил WbICHA в комментарии к вопросу, для приведенных данных корректный тип - это (string | Record<string, any>)[] (массив из строк или объектов в перемешку).

    Ну и вместо any лучше использовать unknown, any - это тип без проверки типов, unknown - это тип который включает в себя все другие типы, в него как и в any тоже можно записать значение любого типа, но в отличии от any при использовании unknown нужно делать либо явное приведение типов, либо рантайм проверки типов.
    Ответ написан
    5 комментариев