Получить TypeScript типизацию возвращаемого объекта - PullRequest
0 голосов
/ 28 мая 2020

Задача

Ниже приведен упрощенный пример того, как мы контролируем и передаем данные в приложении. Он используется во многих местах и ​​работает для перевода данных между пользовательским интерфейсом, API и базой данных. API и UI используют camelCase. База данных использует snake_case.

В настоящее время это неудобная комбинация типов Partial / Pick, чтобы получить некоторый набор текста, где ...

const item = { fooBar: 'something' }
Item.cast(item).value // returns type Partial<ItemModel>
Item.create(item).value // returns type ItemModel

Цель состоит в том, чтобы вернуть реальный возвращаемый тип объекта .

// Examples
const item = { fooBar: 'something' }
Item.cast(item).value // returns { fooBar: 'something' }
Item.cast(item).databaseFormat // returns { foo_bar: 'something' }
Item.create(item).value // returns { id: '{uuid}', fooBar: 'something' }
Item.create(item).databaseFormat // returns { id: '{uuid}', foo_bar: 'something' }

const itemFromDatabase = { id: '{uuid}', foo_bar: 'something', baz: null }
Item.cast(itemFromDatabase).value // returns { id: '{uuid}', fooBar: 'something', baz: null }
Item.cast(itemFromDatabase).databaseFormat // returns { id: '{uuid}', foo_bar: 'something', baz: null }

Есть идеи по этому поводу? Я бы представил это что-то вроде возвращаемого типа Object.entries (), но я не могу понять правильную комбинацию T keyof.

// https://mariusschulz.com/blog/keyof-and-lookup-types-in-typescript
interface ObjectConstructor {
  // ...
  entries<T extends { [key: string]: any }, K extends keyof T>(o: T): [keyof T, T[K]][];
  // ...
}

Код

import camelcaseKeys from 'camelcase-keys'
import snakecaseKeys from 'snakecase-keys'

type Optional<T, K extends keyof T> = Pick<Partial<T>, K> & Omit<T, K>

interface ItemModel {
  id: string
  fooBar: any
  baz?: number
}

interface ItemDatabaseModel {
  id: string
  foo_bar: any
  baz?: number
}

export class Item {

  private _data: Partial<ItemModel>

  public static cast(item: Partial<ItemModel | ItemDatabaseModel>): Item {
    return new this(camelcaseKeys(item))
  }

  public static create(item: Optional<ItemModel | ItemDatabaseModel, 'id'>): Item {
    // Use item.id or add item.id === null to force key
    return new this(camelcaseKeys(item))
  }

  private constructor(input: Partial<ItemModel>) {
    // Validate "input" properties have a Item class property setter, else throw
    // foreach => this[key] = input[key]
  }

  get databaseFormat() { return snakecaseKeys(this._data) }
  get value() { return this._data }

  set id(value: string | null) {
    // automatically generate an ID if null, otherwise validate
    this._data.id = value
  }
  set fooBar(value: any) {
    // validate
    this._data.fooBar = value
  }
  set baz(value: number | null) {
    // validate
    this._data.baz = value
  }
}

1 Ответ

1 голос
/ 29 мая 2020
• 1000 момент машинописи не поддерживает этот вид преобразования автоматически через определение типа, и я предполагаю, что они будут весьма осторожны при добавлении чего-то подобного; конкатенация строковых литералов в определениях типов - это то, что, например, еще не вошло в язык, а то, что вы ищете, к сожалению, немного сложнее.
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...