Typescript — сужение типов объединения для реквизитов вложенных объектов

У меня есть следующий код:

type DesignValueType = "text" | "html" | "image";
type BaseDesignValue<TType extends DesignValueType, TProps> = TProps & {
  type: TType;
};
type DesignValueText = BaseDesignValue<"text", { text: string }>;
type DesignValueHtml = BaseDesignValue<"html", { html: string }>;
type DesignValueImage = BaseDesignValue<"image", { url: string }>;
type DesignValue = DesignValueText | DesignValueHtml | DesignValueImage;
type DesignValues<TInitialValues> = Record<keyof TInitialValues, DesignValue>;

const initialValues = {
  name: { type: "text" as const, text: "" },
  handler: { type: "text" as const, text: "" },
  text: { type: "html" as const, html: "" },
  profile: { type: "image" as const, url: "" },
};

const displayName = (values: DesignValues<typeof initialValues>) => {
  // Property 'text' does not exist on type 'DesignValue'.
  // Property 'text' does not exist on type 'DesignValueHtml'.
  return values.name.text
}

Цель состоит в том, чтобы заставить ТС понять, что реквизит name в values является DesignValueText, каким-то образом сравнив его реквизит type.

Вот ссылка на игровую площадку.

Заранее спасибо!

Вам нужен отображаемый тип: tsplay.dev/WoYa9N

zenly 02.04.2023 22:37

Во-первых, какая часть вашего кода является формулировкой проблемы, а какая — попыткой решения? Во-вторых, почему бы просто не использовать values: typeof initialValues? В конце концов, у initialValues уже есть форма, которую вы пытаетесь кропотливо воссоздать с помощью DesignValues? Почему вы пытаетесь воссоздать тип, который у вас уже есть?

meriton 02.04.2023 23:32
Зод: сила проверки и преобразования данных
Зод: сила проверки и преобразования данных
Сегодня я хочу познакомить вас с библиотекой 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
2
56
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

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

type DesignValueText = { type: "text"; text: string };
type DesignValueHtml = { type: "html"; html: string };
type DesignValueImage = { type: "image"; url: string };
type DesignValue = DesignValueText | DesignValueHtml | DesignValueImage;
type DesignSchema = Record<string, DesignValue["type"]>;
type DesignValues<TInitialValues extends DesignSchema> = {
  [K in keyof TInitialValues]: TInitialValues[K] extends "text"
    ? DesignValueText
    : TInitialValues[K] extends "html"
    ? DesignValueHtml
    : TInitialValues[K] extends "image"
    ? DesignValueImage
    : never;
};

const schema = {
  name: "text",
  handler: "text",
  text: "html",
  profile: "image",
} satisfies DesignSchema;

const displayName = (values: DesignValues<typeof schema>) => {
  return values.name.text
}

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

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

Вам нужно сопоставить ключи и извлечь правильный тип:

type DesignValues<TInitialValues extends Record<any, DesignValue>> = {
    [K in keyof TInitialValues]: Extract<DesignValue, { type: TInitialValues[K]["type"] }>;
};

const displayName = (values: DesignValues<typeof initialValues>) => {
  return values.name.text // okay
}

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

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

Похожие вопросы

Соединение с надбазой возвращает неопределенное значение
Почему ESLint сообщает об ошибке @typescript/no-redeclare для объединенного интерфейса и переменной?
Как выполнить горячую перезагрузку Typescript Lambda с помощью локального стека
Jest-тестирование службы, использующей Neo4J и MongoDb, возвращает ошибку: «TypeError: невозможно прочитать свойства неопределенного (чтение« inspectModules »)»
Infer не удовлетворяет ограничениям типа?
React — динамически импортировать компонент или функцию не по умолчанию
Разбивка таблицы MUI DataGrid не работает
Сфокусируйте родителя на дочернем элементе с помощью React Hooks
Ошибка: объекты недействительны в качестве дочернего элемента React — при попытке асинхронного выполнения на page.tsx в nextjs
Ошибка NextJS: гидратация не удалась, поскольку исходный пользовательский интерфейс не соответствует тому, что было отображено на сервере. в папке экспериментального каталога приложения