Задать вопрос
Fragster
@Fragster
помогло? отметь решением!

Почему ругается на такой генерик?

вроде бы простейшая фигня:

export function lowercasedObject<T extends { [k: string]: unknown }>(object: T): T {
  return Object.fromEntries(Object.entries(object).map(([key, value]) => [key, typeof value === 'string' ? value.toLowerCase() : value]))
}

но ругается на return
Type '{ [k: string]: unknown; }' is not assignable to type 'T'.
'{ [k: string]: unknown; }' is assignable to the constraint of type 'T', but 'T' could be instantiated with a different subtype of constraint '{ [k: string]: unknown; }'.ts(2322)
  • Вопрос задан
  • 129 просмотров
Подписаться 2 Простой 4 комментария
Помогут разобраться в теме Все курсы
  • Skypro
    Frontend-разработчик с нуля
    9 месяцев
    Далее
  • Stepik
    TypeScript с 0 до ПРО | Решение задач по TS, разбор сложных тем
    1 неделя
    Далее
  • Нетология
    Node.js для backend-разработки
    6 месяцев
    Далее
Пригласить эксперта
Ответы на вопрос 1
Fragster
@Fragster Автор вопроса
помогло? отметь решением!
Ответ на "почему ругается" такой - на вход может быть подан объект с полями более узкого, чем string типами, типа такого:
type MyEntity = {
  name: string,
  type: 'Type1' | 'Type2'
}

и на выходе type не будет соответствовать исходному типу, будет просто string. Так что по хорошему должно быть что-то типа
export function lowercasedObject<T extends Record<string, unknown>, R = {
  [K in keyof T]: T[K] extends string ? string : T[K]
}> (obj: T): R {
  const res = {} as R
  for (let k of (Object.keys(obj) as Extract<keyof R, string>[])) {
    res[k] = (typeof obj[k] === 'string' ? obj[k].toLowerCase() : obj[k]) as R[typeof k]
  }
  return res
}

но и это не совсем то, ибо в общем случае сломаются union более узкого типа и не строки, что тоже надо как-то обрабатывать

UPD: в общем, нужно определять наследование string в два этапа, см песочницу

в итоге получается что-то типа такого в различных вариациях

type ReplaceStringParts<T> = T extends string ? string : T;

export function lowercasedObject<T extends Record<string, unknown>, R = {
  [K in keyof T]: ReplaceStringParts<T[K]>
}> (obj: T): R {
  const res = {} as R
  for (let k of (Object.keys(obj) as Extract<keyof R, string>[])) {
    res[k] = (typeof obj[k] === 'string' ? obj[k].toLowerCase() : obj[k]) as R[typeof k]
  }
  return res
}
Ответ написан
Комментировать
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы