我有一类用作装饰器的函数:
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)
}
....
}
这似乎不太干。可以改进吗?
答案 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;
});
所以我认为会对你有用,但它非常丑陋。你重复自己可能会更快乐。它取决于你。希望有所帮助!祝你好运!