#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, показывающей ваше второе обновление. Похоже, это действительно работает, слишком плохо, что приведение необходимо, поскольку, похоже, оно должно быть выведено.