Сохранять `?:` необязательные типы при циклическом переборе

#typescript

#typescript

Вопрос:

Я создал тип, который делает все свойства, кроме тех, которые я специально выбрал, не обязательными.

 export type OptionalProps<Input, Excl extends keyof Input> = {
    [P in Exclude<keyof Input, Excl>]: Input[P];
} amp;
    Optional<Input>;
 

Проблема в том, что это сделает ?: свойства определенными, если я не укажу их напрямую.

Я пытался undefined extends Input[P] ? '' : Input[P] , но это не сработало, он просто присваивается '' в качестве типа. Назначение undefined заставляет меня всегда указывать undefined .

Не уверен, как отобразить вне []

Игровая площадка

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

1. Не могли бы вы поделиться воспроизводимым примером и явно определить, чего вы ожидаете. Спасибо

Ответ №1:

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

 type PartialExceptFor<T, K extends keyof T> =
  Pick<T, K> amp; Partial<Omit<T, K>>;
 

Здесь мы просто используем предоставленные типы утилит, такие как Pick , Partial , и Omit для создания нужного вам типа. Давайте протестируем это:

 interface Foo {
  a: string;
  b: number;
  c?: string;
  d?: number;
}

type FB = PartialExceptFor<Foo, "b" | "d">;
// type FB = Pick<Foo, "b" | "d"> amp; Partial<Pick<Foo, "a" | "c">>
 

Это правильно, хотя трудно сказать, посмотрев на краткую информацию IntelliSense для типа. Один из способов справиться с этим — заставить компилятор просмотреть свойства и создать единый расширенный тип объекта:

 type PartialExceptFor<T, K extends keyof T> =
  Pick<T, K> amp; Partial<Omit<T, K>> extends infer O ? { [P in keyof O]: O[P] } : never;
 

extends infer O Часть использует вывод в условных типах для «копирования» типа в новый параметр типа O , с помощью которого мы затем сопоставляем каждое свойство с самим { [P in keyof O]: O[P] } собой .

Теперь краткая информация в IntelliSense дает вам это:

 type FB = PartialExceptFor<Foo, "b" | "d">;
/* type FB = {
    b: number;
    d?: number | undefined;
    a?: string | undefined;
    c?: string | undefined;
} */
 

Это то, чего мы хотели. Свойства b и d не были изменены ( b по-прежнему требуются и d по-прежнему являются необязательными), но остальные свойства a и c были сделаны необязательными.

Ссылка на игровую площадку для кода

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

1. Потрясающий ответ! Я должен переключиться pick и omit получить желаемый результат (ввод ключа похож на белый список для того, что должно стать частичным, прямо сейчас ввод ключа представляет собой белый список для материалов, которые не должны становиться частичными, но это было трудно увидеть / неясно из-за того, как я задал свой вопрос)