Consider this example of a unique Decorator Factory Builder - a builder that constructs Decorator Factories to define metadata for forms:
interface FormFieldOptions {
name?: string;
label?: string;
format?: string;
}
type FormProperties = Record<string | symbol, FormFieldOptions>;
function FormFieldPropertyDecorator<K extends keyof FormFieldOptions>(
option: K,
defaultValue?: FormFieldOptions[K] | 'propertyKey',
) {
return function FormFieldProperty(value: FormFieldOptions[K] | null) {
return function (target: unknown, propertyKey: string | symbol) {
// ... Reflection magic goes here ...
};
};
}
The type
value: FormFieldOptions[K] | null
is converted to value: FormFieldOptions[K]
when using the Decorator Factories:
// const FormField: (value: string) => (target: unknown, propertyKey: string | symbol) => void
export const FormField = FormFieldPropertyDecorator('name', 'propertyKey');
// const Label: (value: string) => (target: unknown, propertyKey: string | symbol) => void
export const Label = FormFieldPropertyDecorator('label');
// const Format: (value: string) => (target: unknown, propertyKey: string | symbol) => void
export const Format = FormFieldPropertyDecorator('format');
A similar transformation occurs with the type
FormFieldProperty(value: FormFieldOptions[K] | undefined)
However, the optional modifier ?
remains in the returned function types:
Using
return function FormFieldProperty(value?: FormFieldOptions[K] | null) {
// const FormField: (value?: string) => (target: unknown, propertyKey: string | symbol) => void
export const FormField = FormFieldPropertyDecorator('name', 'propertyKey');
// const Label: (value?: string) => (target: unknown, propertyKey: string | symbol) => void
export const Label = FormFieldPropertyDecorator('label');
// const Format: (value?: string) => (target: unknown, propertyKey: string | symbol) => void
export const Format = FormFieldPropertyDecorator('format');
Why do null
or undefined
types disappear, while the optional modifier remains unchanged?
PS: The main goal here is to make value
mandatory if defaultValue
is not set, but optional otherwise