diff --git a/lib/intersection-type.helper.ts b/lib/intersection-type.helper.ts
index dd10af03..cd4e5753 100644
--- a/lib/intersection-type.helper.ts
+++ b/lib/intersection-type.helper.ts
@@ -6,49 +6,38 @@ import {
inheritValidationMetadata,
} from './type-helpers.utils';
-export function IntersectionType(
- target: Type,
- source: Type,
-): MappedType;
+// https://stackoverflow.com/questions/50374908/transform-union-type-to-intersection-type
+type UnionToIntersection = (U extends any ? (k: U) => void : never) extends (
+ k: infer I,
+) => void
+ ? I
+ : never;
-export function IntersectionType(
- target: Type,
- sourceB: Type,
- sourceC: Type,
-): MappedType;
+type ClassRefsToConstructors = {
+ [U in keyof T]: T[U] extends Type ? V : never;
+};
-export function IntersectionType(
- target: Type,
- sourceB: Type,
- sourceC: Type,
- sourceD: Type,
-): MappedType;
-
-export function IntersectionType(
- classA: Type,
- ...classRefs: T
-): MappedType {
- const allClassRefs = [classA, ...classRefs];
+type Intersection = Type<
+ UnionToIntersection[number]>
+>;
+export function IntersectionType(...classRefs: T) {
abstract class IntersectionClassType {
constructor() {
- allClassRefs.forEach((classRef) => {
+ classRefs.forEach((classRef) => {
inheritPropertyInitializers(this, classRef);
});
}
}
- allClassRefs.forEach((classRef) => {
+ classRefs.forEach((classRef) => {
inheritValidationMetadata(classRef, IntersectionClassType);
inheritTransformationMetadata(classRef, IntersectionClassType);
});
- const intersectedNames = allClassRefs.reduce(
- (prev, ref) => prev + ref.name,
- '',
- );
+ const intersectedNames = classRefs.reduce((prev, ref) => prev + ref.name, '');
Object.defineProperty(IntersectionClassType, 'name', {
value: `Intersection${intersectedNames}`,
});
- return IntersectionClassType as MappedType;
+ return IntersectionClassType as Intersection;
}
diff --git a/tests/intersection-type-multiple.helper.spec.ts b/tests/intersection-type-multiple.helper.spec.ts
index b8239efd..ecd9b2f1 100644
--- a/tests/intersection-type-multiple.helper.spec.ts
+++ b/tests/intersection-type-multiple.helper.spec.ts
@@ -31,7 +31,23 @@ describe('IntersectionType', () => {
patronymic!: string;
}
- class UpdateUserDto extends IntersectionType(ClassA, ClassB, ClassC) {}
+ class ClassD {
+ @IsString()
+ alpha = 'defaultStringAlpha';
+ }
+
+ class ClassE {
+ @IsString()
+ beta = 'defaultStringBeta';
+ }
+
+ class UpdateUserDto extends IntersectionType(
+ ClassA,
+ ClassB,
+ ClassC,
+ ClassD,
+ ClassE,
+ ) {}
describe('Validation metadata', () => {
it('should inherit metadata for all properties from class A and class B', () => {
@@ -45,6 +61,8 @@ describe('IntersectionType', () => {
'lastName',
'hash',
'patronymic',
+ 'alpha',
+ 'beta',
]);
});
describe('when object does not fulfil validation rules', () => {
@@ -74,6 +92,8 @@ describe('IntersectionType', () => {
updateDto.lastName = 'lastNameTest';
updateDto.login = 'mylogintesttest';
updateDto.patronymic = 'patronymicTest';
+ updateDto.alpha = 'alphaTest';
+ updateDto.beta = 'betaTest';
const validationErrors = await validate(updateDto);
expect(validationErrors.length).toEqual(0);
@@ -105,6 +125,8 @@ describe('IntersectionType', () => {
expect(updateUserDto.login).toEqual('defaultLoginWithMin10Chars');
expect(updateUserDto.firstName).toEqual('defaultFirst');
expect(updateUserDto.hash).toEqual('defaultHashWithMin5Chars');
+ expect(updateUserDto.alpha).toEqual('defaultStringAlpha');
+ expect(updateUserDto.beta).toEqual('defaultStringBeta');
});
});
});