打字稿可以使这段代码更干吗?

时间:2017-12-16 18:54:27

标签: javascript typescript

我有一类用作装饰器的函数:

interface SchemaDefinition {
    type: any;
    label?: string | Function;
    optional?: boolean | Function;
    min?: number | boolean | Date | Function;
    max?: number | boolean | Date | Function;
    minCount?: number | Function;
    maxCount?: number | Function;
    allowedValues?: any[] | Function;
    decimal?: boolean;
    exclusiveMax?: boolean;
    exclusiveMin?: boolean;
    regEx?: RegExp | RegExp[];
    custom?: Function;
    blackbox?: boolean;
    autoValue?: Function;
    defaultValue?: any;
    trim?: boolean;
}

class Decorators {
    static Type(value: Pick<SchemaDefinition, 'type'>) {
        return SchemaDecorators.extendSchema('type', value)
    }

    static Min(value: Pick<SchemaDefinition, 'min'>) {
        return SchemaDecorators.extendSchema('min', value)
    }

    static Max(value: Pick<SchemaDefinition, 'max'>) {
        return SchemaDecorators.extendSchema('max', value)
    }

    ....
}

这似乎不太干。可以改进吗?

1 个答案:

答案 0 :(得分:0)

TypeScript并不总是让DRY变得非常简单,特别是因为所有类型信息都在运行时被擦除。这意味着有时不重复自己的唯一方法是创建一个虚拟运行时对象,其类型信息可以由编译器推断。

这是尝试做DRY,你可能认为这是不值得的。首先,我们需要在运行时循环遍历SchemaDefinition的键以编程方式创建Decorators。我创建了一个带有虚拟未定义值的SchemaDefinitionClass,以便我们可以获得这些键:

const ω: never = (void 0)!;
class SchemaDefinitionClass {
    type: any = ω;
    label?: string | Function = ω;
    optional?: boolean | Function = ω;
    min?: number | boolean | Date | Function = ω;
    max?: number | boolean | Date | Function = ω;
    minCount?: number | Function = ω;
    maxCount?: number | Function = ω;
    allowedValues?: any[] | Function = ω;
    decimal?: boolean = ω;
    exclusiveMax?: boolean = ω;
    exclusiveMin?: boolean = ω;
    regEx?: RegExp | RegExp[] = ω;
    custom?: Function = ω;
    blackbox?: boolean = ω;
    autoValue?: Function = ω;
    defaultValue?: any = ω;
    trim?: boolean = ω;
}
interface SchemaDefinition extends SchemaDefinitionClass { }

您可以验证SchemaDefinition的定义与之前相同。我想将所有值明确地设置为undefined正在重复自己,但至少它是一个短暂的重复。

哦,我不知道SchemaDecorators.extendSchema()会返回什么。我将为它创建一个存根返回类型;根据需要改变它:

type Foo<K,V> = {
  foo: K;
  bar: V;
}
declare const SchemaDecorators: {
  extendSchema<K extends string, V>(k: K, v: V): Foo<K, V>;
}

现在我不是将Decorators作为一个带有一堆静态方法的类,而是将它作为一个带有一堆方法属性的对象。它主要是相同的东西,如果你需要它可以与一个类合并。

const Decorators: {
  [K in keyof SchemaDefinition]: (value: Pick<SchemaDefinition, K>) => Foo<SchemaDefinition, Pick<SchemaDefinition, K>>
} = {} as any;

请注意!上面的定义意味着静态方法是小写的,与SchemaDefinition的键名称相同,而不是CamelCase。这是不可避免的,除非你想写出像{type: 'Type', ...}这样的地图,我不会这样做。

好的,让我们填充Decorators

Object.keys(new SchemaDefinitionClass()).forEach(<K extends keyof SchemaDefinition>(k: K) => { 
  Decorators[k] = ((value: Pick<SchemaDefinition, K>) => SchemaDecorators.extendSchema(k, value)) as any;
});

所以我认为会对你有用,但它非常丑陋。你重复自己可能会更快乐。它取决于你。希望有所帮助!祝你好运!