У меня есть следующий код:
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
.
Вот ссылка на игровую площадку.
Заранее спасибо!
Во-первых, какая часть вашего кода является формулировкой проблемы, а какая — попыткой решения? Во-вторых, почему бы просто не использовать values: typeof initialValues
? В конце концов, у initialValues
уже есть форма, которую вы пытаетесь кропотливо воссоздать с помощью DesignValues
? Почему вы пытаетесь воссоздать тип, который у вас уже есть?
Я смог заставить его работать, используя некоторые условные выражения и заменив 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
}
Вам нужен отображаемый тип: tsplay.dev/WoYa9N