typescript 为什么高阶泛型函数会从返回的函数参数中删除falsy类型?

svmlkihl  于 2023-06-30  发布在  TypeScript
关注(0)|答案(1)|浏览(107)

以这个通用的Decorator Factory工厂为例-一个构建Decorator Factory以定义表单元数据的工厂:

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) {
      // ... Some reflect-metadata magic ...
    };
  };
}

在示例化装饰器工厂时,类型value: FormFieldOptions[K] | null被强制为value: FormFieldOptions[K]

// 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');

使用FormFieldProperty(value: FormFieldOptions[K] | undefined)类型时也会发生相同的擦除
但是一个可选的修饰符?是保留的,并且存在于返回的函数类型中:
使用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');

为什么nullundefined类型会被擦除,而可选修饰符却不会?
PS:我这里的主要目标是,如果defaultValue未定义,则value是必需的,否则是可选的

gojuced7

gojuced71#

我不完全确定为什么你认为类型是强制的,你的IDE显示了吗?使用第一个定义,您必须调用返回的函数(FormFieldProperty),如其签名所描述的,即类型为FormFieldOptions[K]或值为null;这两个都很好:

export const Label = FormFieldPropertyDecorator('label');
Label("something");
Label(null);

如果你想实现你所描述的行为,你可以使用函数重载:

type InternalDecorator = (target: unknown, propertyKey: (string | symbol)) => void;

function FormFieldPropertyDecorator<K extends keyof FormFieldOptions>(
    option: K,
): (value: string) => InternalDecorator;
function FormFieldPropertyDecorator<K extends keyof FormFieldOptions>(
    option: K,
    defaultValue: FormFieldOptions[K] | 'propertyKey',
): (value?: string) => InternalDecorator;

function FormFieldPropertyDecorator<K extends keyof FormFieldOptions>(
    option: K,
    defaultValue?: FormFieldOptions[K] | 'propertyKey',
) {
    return function FormFieldProperty(value: FormFieldOptions[K]) {
        return function (target: unknown, propertyKey: string | symbol) {
            // ... Some reflect-metadata magic ...
        };
    };
}

export const Label1 = FormFieldPropertyDecorator('label');
Label1("something"); // OK
Label1();            // not OK

export const Label2 = FormFieldPropertyDecorator('label', "something");
Label2("something"); // OK
Label2();            // also OK

相关问题