Машинописный ключ частичного перекрытия

#typescript #keyof

#typescript #ключ

Вопрос:

Я хотел бы ввести функцию вставки БД, которая допускает значения по умолчанию: (я использую SetOptional для type-fest)

 function defaultInsert<T, D = Partial<T>>(data: SetOptional<T, keyof D>, defaults: D) {
  

Что я пытаюсь сказать с помощью SetOptional, так это то, что объект данных должен содержать что-либо в T, не указанное в defaults (D), но разрешено перезаписывать что-либо в defaults .

К сожалению, это приводит к следующей ошибке

 Type 'keyof D' does not satisfy the constraint 'keyof T'.
  Type 'string | number | symbol' is not assignable to type 'keyof T'.
    Type 'string' is not assignable to type 'keyof T'.(2344)
  

Игровая площадка Typescript для более сложного примера.

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

Большое спасибо

РЕДАКТИРОВАТЬ: по предложению @Alex Chashin, другая игровая площадка TS использует ключи как способ определения значений по умолчанию.

РЕДАКТИРОВАНИЕ 2: обновленная игровая площадка с решением, предоставленным в UPD2 @Alex Chashin

EDIT3: обновлен предыдущий пример, так что значения по умолчанию также могут быть опущены: игровая площадка

Ответ №1:

UPD2: Итак, единственное, что я мог придумать, что не слишком сложно для существования в этом мире, это (игровая <a rel="noreferrer noopener nofollow" href="http:// function defaultInsert( data: Omit amp; Partial<Pick>, defaults: Pick ): void { // Hover over this variable to see its type const doc = { …data, …defaults } as T insert(doc) }» rel=»nofollow noreferrer»>площадка ts):

 function defaultInsert<T, D extends keyof T>(
  data: Omit<T, D> amp; Partial<Pick<T, D>>,
  defaults: Pick<T, D>
): void {
  // Hover over this variable to see its type
  const doc = { ...data, ...defaults } as T
  insert<T>(doc)
}
  

Это проходит тесты, которые вы предоставили, но, к сожалению {...data, ...default} , не предполагается T , что это так, поэтому вам нужно его использовать. Я не думаю, что это имеет большое значение, поскольку этот тип приведения занимает всего 4 символа. Единственная проблема заключается в том, что вы должны явно предоставлять ключи для D каждого раза, когда вам нужно при написании примера keyof typeof personDefaults
UPD:
Ссылка на игровую площадку TS с одним из возможных решений: игровая площадка

Оригинальный ответ:

Так Partial<T> что уже делает все ключи T необязательными, вам не нужно использовать SetOptional после того, как вы это сделали Partial . Если вы хотите, чтобы все ключи данных были необязательными, просто используйте это:

 function defaultInsert<T>(data: Partial<T>, defaults: T) {
  // ...
}
  

Обратите внимание, что defaults имеет тип T , нет Partial<T> , потому что, если бы это было Partial<T> так, вы могли бы предоставить документ, который не является полным as data , и документ, который не является полным as defaults , поэтому их объединение не даст полного документа, что может быть проблемой для вас. Если это не так, замените T на Partial<T> , трудно судить, потому что вы не предоставили весь код.

Если вы хотите, чтобы только некоторые ключи были необязательными, сделайте это:

 function defaultInsert<T, Keys extends string>(
  data: SetOptional<T, Keys>, 
  defaults: { [key in Keys]: T[key] }
) {
  // ...
}
  

Таким образом, вам нужно будет указать значения по умолчанию только для необязательных ключей, но не для всех
Вы также могли бы сделать defaults из типа

 Omit<Partial<T>, Keys> amp; { [key in Keys]: T[key] }
// or if you use your `SetOptional`
SetOptional<T, Exclude<keyof T, Keys>>
  

Чтобы typescript не жаловался, когда вы предоставляете значения по умолчанию для ключей, которые не являются необязательными

затем используйте, как

 defaultInsert<{ foo: number, bar: string }, 'foo'>(
  { bar: 'abc' },
  { foo: 12345 }
)
  

Комментарии:

1. Что касается вашего первого абзаца, я хочу установить ключи, предоставленные в D, как необязательные в T, где D является частью T. Я действительно хочу, чтобы только некоторые поля T были по умолчанию и, следовательно, необязательными в данных. Я пытаюсь определить, какие из них относятся к типу D, как вы можете видеть в ссылке на игровую площадку. Возможно, я неправильно понял ваши последние примеры, поскольку попытка его продолжает выдавать ошибки (см. Редактирование в основном сообщении)

2. @EvertEtienne, проверьте ссылку на ts playground в моем обновленном ответе, там он не показывает ошибок при вызове функции, но он также не определяет тип { ...data, ...defaults } , я постараюсь придумать что-нибудь получше, я сообщу вам, если найду другое решение

3. @EvertEtienne Итак, я разместил ссылку на другой вариант, он в основном такой же, но выглядит лучше, но пока я не могу придумать что-то лучшее

4. Большое спасибо. Ваша ссылка, похоже, не работает для меня, но я обновил свой пост с помощью playground, показывающей ваше второе обновление. Похоже, это действительно работает, слишком плохо, что приведение необходимо, поскольку, похоже, оно должно быть выведено.