Pick<Type, Keys>, где Type — Partial<Type> позволяет назначать несуществующие свойства

Чего я хочу достичь

Я хочу получить подмножество конкретных/предопределенных свойств, используя Pick<Partial<Type>, Keys> на предоставленном Type. Предопределенные/конкретные свойства могут существовать, а могут и не существовать в предоставленном Type, но если их нет, нам не должно быть разрешено назначать их для возвращаемого типа.

Что я пробовал

Я попытался создать тип SubsetPick<T extends Partial<PropertyType>> = Pick<T, Keys>, но, вероятно, из-за типа Partial<PropertyType> он возвращает Keys, указанный в Pick<T, Keys>, даже если они не существуют в предоставленном Type.

Пример

Вот пример, воспроизводящий то, что я пытаюсь сделать:

interface Properties {
  name: string;
  animal: boolean;
  plant: boolean;
  fly: boolean;
  swim: boolean;
  walk: boolean;
}

type Bird = Pick<Properties, 'name' | 'animal' | 'fly'>;

// this doesn't work
type SubsetPick<T extends Partial<Properties>> = Pick<T, 'fly' | 'swim' | 'walk'>

// bad: we can assign properties `swim` and `walk` that don't exist on type `Bird`
const birdSubset: SubsetPick<Bird> = {
  fly: true,
  swim: true, // no error
  walk: true, // no error
}

Детская площадка

Я не понимаю, в чем цель. Ваш InferPick<T> по сути просто T, но для Plant это undefined. Но... вы хотите const plant: InferPick<Plant> = undefined, а не const plant: InferPick<Plant> = {}? Я вообще не вижу в этом пользы Pick.

jcalz 06.08.2024 15:27

см. предыдущий комментарий. Может быть, вы ищете что-то вроде ссылку на игровую площадку , где вы явно запрещаете свойства, которые вы не выбираете? Но даже в этом случае я предполагаю, что вы хотите, чтобы растение было {}, а не undefined. Я близко? Я мог бы написать ответ или найти повторяющийся вопрос, если это то, что вы ищете. Если нет, пожалуйста отредактируйте, чтобы уточнить намерение.

jcalz 06.08.2024 15:34

@jcalz тип Plant не имел значения и мог привлечь много внимания к тому, чего я пытаюсь достичь. Я обновил фрагмент, чтобы попытаться более четко представить то, что я хочу... Я хочу иметь возможность получить подмножество конкретных свойств, используя Pick<Type, Keys> прилагается Type

j3ff 06.08.2024 16:08

Однако ваш ConditionalPick не «работает», это просто пустяк. Вы можете написать const bird: Bird = и получить желаемое поведение в обоих случаях, как показано по ссылке на игровую площадку. В чем проблема?

jcalz 06.08.2024 16:11

ConditionalPick не помогает продемонстрировать то, что вы ищете. Не могли бы вы посмотреть PickOnly в ссылку на эту игровую площадку и сообщить мне, это то, что вы ищете, или нет? Я полагаю, вы могли бы разделить его на оригинал Pick, а затем позже вернуться и попытаться исключить другие элементы, как показано в этой ссылке на игровую площадку, но я не уверен, что это вам дает. В любом случае, пожалуйста, посмотрите на них и дайте мне знать, так как я думаю, что одно или оба могут быть тем, чего вы пытаетесь достичь.

jcalz 06.08.2024 16:35

@jcalz, спасибо, что приложили некоторые усилия к моему вопросу, но я считаю, что вы слишком много внимания уделяете образцу и пытаетесь понять его смысл, тогда как я пытался представить только фиктивные типы. Я скорректировал начало проблемы, чтобы объяснить, что я хочу иметь возможность получать подмножество определенных ключей, ЕСЛИ они существуют в указанном типе. Надеюсь, это имеет больше смысла...

j3ff 06.08.2024 16:36

Пожалуйста, прочитайте мой предыдущий комментарий и ответьте на него конкретно.

jcalz 06.08.2024 16:38

Спасибо @jcalz, ваша игровая площадка не решила мою проблему, но вдохновила меня копать в другом направлении, и я нашел ответ

j3ff 06.08.2024 18:23

Боюсь, ваш ответ не имеет для меня особого смысла, как и вопрос. Было бы полезно узнать, какие именно типы ввода/вывода вы ищете, но на данный момент я полагаю, что дальнейшие комментарии и правки вряд ли будут плодотворными, поэтому я воздержусь от этого. Извините, мы не смогли эффективно общаться!

jcalz 06.08.2024 18:32

Извините, если это было недостаточно ясно, но я ценю время и усилия, которые вы вложили в это... вы помогли мне найти решение.

j3ff 06.08.2024 18:40
Зод: сила проверки и преобразования данных
Зод: сила проверки и преобразования данных
Сегодня я хочу познакомить вас с библиотекой Zod и раскрыть некоторые ее особенности, например, возможности валидации и трансформации данных, а также...
Как заставить Remix работать с Mantine и Cloudflare Pages/Workers
Как заставить Remix работать с Mantine и Cloudflare Pages/Workers
Мне нравится библиотека Mantine Component , но заставить ее работать без проблем с Remix бывает непросто.
Угловой продивер
Угловой продивер
Оригинал этой статьи на турецком языке. ChatGPT используется только для перевода на английский язык.
TypeScript против JavaScript
TypeScript против JavaScript
TypeScript vs JavaScript - в чем различия и какой из них выбрать?
Синхронизация localStorage в масштабах всего приложения с помощью пользовательского реактивного хука useLocalStorage
Синхронизация localStorage в масштабах всего приложения с помощью пользовательского реактивного хука useLocalStorage
Не все нужно хранить на стороне сервера. Иногда все, что вам нужно, это постоянное хранилище на стороне клиента для хранения уникальных для клиента...
Что такое ленивая загрузка в Angular и как ее применять
Что такое ленивая загрузка в Angular и как ее применять
Ленивая загрузка - это техника, используемая в Angular для повышения производительности приложения путем загрузки модулей только тогда, когда они...
0
10
67
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Я понял это, вдохновившись примерами игровых площадок, представленными в комментариях @jcalz...

Используя Extract<Type, Union>, можно извлечь только те ключи, которые можно назначить Type, и избежать наличия неназначаемых свойств в возвращаемом типе. Таким образом, вместо использования Pick<Type, Keys> вы можете создать возвращаемый объект правильного типа.

interface Properties {
  name: string;
  animal: boolean;
  plant: boolean;
  fly: boolean;
  swim: boolean;
  walk: boolean;
}

type Bird = Pick<Properties, 'name' | 'animal' | 'fly'>;

// this works
type SubsetPick<T extends Partial<Properties>> = {
  [P in Extract<keyof T, 'fly' | 'swim' | 'walk'>]: T[P];
};

// good: we can only assign property that exists on type `Bird`
// and that are part of the subset declared in `SubsetPick`
const birdSubset: SubsetPick<Bird> = {
  fly: true,
  swim: true, // error
}

Детская площадка

Учитывая ваш пример, это имеет мало смысла. Вы можете заменить его всего на type GenericPick<T> = T, и вы все равно получите сообщение об ошибке swim. См. ссылку на эту игровую площадку . Более того, ваша версия Extract фактически удаляет из типа такие вещи, как name, поэтому вы получаете сообщение об ошибке, как показано в этой ссылке на игровую площадку. Это действительно то, что вы пытаетесь сделать? Если это так, вам следует отредактировать вопрос, чтобы сделать это явным.

jcalz 06.08.2024 18:31

Извините, я не знаю, как сделать это более явным, поскольку это указано в верхней части описания: «Я хочу получить подмножество конкретных/предопределенных свойств... предопределенные/определенные свойства могут существовать, а могут и не существовать». по предоставленному типу, но если они этого не делают, нам не должно быть разрешено назначать его для возвращаемого типа». но если у вас есть идеи, как сделать это более понятным, не стесняйтесь.

j3ff 06.08.2024 18:36

Другие вопросы по теме