Skip to content

Commit 883c2b8

Browse files
authored
Merge pull request #122 from nobrainr/fix/strict-schema-class-typing
Fix/strict schema class typing
2 parents 754c4b2 + 2a9fcd0 commit 883c2b8

File tree

5 files changed

+46
-13
lines changed

5 files changed

+46
-13
lines changed

package-lock.json

+3-3
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@
6868
"typedoc": "^0.15.0",
6969
"typedoc-plugin-external-module-name": "^2.0.0",
7070
"typedoc-plugin-internal-external": "^2.0.1",
71-
"typescript": "^3.4.2",
71+
"typescript": "3.5.3",
7272
"webpack": "4.38.0",
7373
"webpack-cli": "^3.3.0"
7474
},

src/morphism.ts

+13-3
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,7 @@ function transformItems<T, TSchema extends Schema<T | {}>>(schema: TSchema, type
7272
tree = new MorphismSchemaTree(schema);
7373
}
7474

75-
function mapper(source: any) {
75+
const mapper: Mapper<TSchema> = (source: any) => {
7676
if (!source) {
7777
return source;
7878
}
@@ -96,7 +96,7 @@ function transformItems<T, TSchema extends Schema<T | {}>>(schema: TSchema, type
9696
return transformValuesFromObject(object, tree, [object], jsObject);
9797
}
9898
}
99-
}
99+
};
100100

101101
return mapper;
102102
}
@@ -148,7 +148,17 @@ function morphism<TSchema extends Schema, TDestination>(
148148
type: Constructable<TDestination>
149149
): Mapper<TSchema, TDestination>; // morphism({}, null, T) => mapper(S) => T
150150

151-
function morphism<TSchema extends Schema, Target>(schema: TSchema, items: SourceFromSchema<TSchema>, type: Constructable<Target>): Target; // morphism({}, {}, T) => T
151+
function morphism<
152+
TSchema = Schema<DestinationFromSchema<Schema>, SourceFromSchema<Schema>>,
153+
Target = never,
154+
Source extends SourceFromSchema<TSchema> = SourceFromSchema<TSchema>
155+
>(schema: TSchema, items: Source, type: Constructable<Target>): Target; // morphism({}, {}, T) => T
156+
157+
function morphism<
158+
TSchema = Schema<DestinationFromSchema<Schema>, SourceFromSchema<Schema>>,
159+
Target = never,
160+
Source extends SourceFromSchema<TSchema> = SourceFromSchema<TSchema>
161+
>(schema: TSchema, items: Source[], type: Constructable<Target>): Target[]; // morphism({}, [], T) => T[]
152162

153163
function morphism<Target, Source, TSchema extends Schema<Target, Source>>(
154164
schema: TSchema,

src/types.ts

+6-6
Original file line numberDiff line numberDiff line change
@@ -37,17 +37,17 @@ export type StrictSchema<Target = any, Source = any> = {
3737
| ActionString<Source>
3838
| ActionFunction<Target, Source, Target[destinationProperty]>
3939
| ActionAggregator<Source>
40-
| ActionSelector<Source, Target[destinationProperty]>
41-
| StrictSchema<Target[destinationProperty], Source>
40+
| ActionSelector<Source, Target>
41+
| StrictSchema<Target[destinationProperty], Source>;
4242
} & { [SCHEMA_OPTIONS_SYMBOL]?: SchemaOptions<Target> };
4343
export type Schema<Target = any, Source = any> = {
4444
/** `destinationProperty` is the name of the property of the target object you want to produce */
4545
[destinationProperty in keyof Target]?:
4646
| ActionString<Source>
4747
| ActionFunction<Target, Source, Target[destinationProperty]>
4848
| ActionAggregator<Source>
49-
| ActionSelector<Source, Target[destinationProperty]>
50-
| Schema<Target[destinationProperty], Source>
49+
| ActionSelector<Source, Target>
50+
| Schema<Target[destinationProperty], Source>;
5151
} & { [SCHEMA_OPTIONS_SYMBOL]?: SchemaOptions<Target | any> };
5252

5353
export type Actions<Target, Source> = ActionFunction<Target, Source> | ActionAggregator | ActionString<Target> | ActionSelector<Source>;
@@ -172,6 +172,6 @@ export type DestinationFromSchema<T> = T extends StrictSchema<infer U> | Schema<
172172
export type ResultItem<TSchema extends Schema> = DestinationFromSchema<TSchema>;
173173

174174
export interface Mapper<TSchema extends Schema | StrictSchema, TResult = ResultItem<TSchema>> {
175-
(data: SourceFromSchema<TSchema>[]): TResult[];
176-
(data: SourceFromSchema<TSchema>): TResult;
175+
(data?: SourceFromSchema<TSchema>[] | null): TResult[];
176+
(data?: SourceFromSchema<TSchema> | null): TResult;
177177
}

src/typescript.spec.ts

+23
Original file line numberDiff line numberDiff line change
@@ -161,6 +161,29 @@ describe('Typescript', () => {
161161
morphism<StrictSchema<D1, S1>>({ a: ({ _a }) => _a.toString() });
162162
morphism<StrictSchema<D1, S1>>({ a: ({ _a }) => _a.toString() });
163163
});
164+
165+
it('shoud infer result type from source when a class is provided', () => {
166+
class Source {
167+
constructor(public id: number, public ugly_field: string) {}
168+
}
169+
170+
class Destination {
171+
constructor(public id: number, public field: string) {}
172+
}
173+
174+
const source = [new Source(1, 'abc'), new Source(1, 'def')];
175+
176+
const schema: StrictSchema<Destination, Source> = {
177+
id: 'id',
178+
field: 'ugly_field'
179+
};
180+
const expected = [new Destination(1, 'abc'), new Destination(1, 'def')];
181+
182+
const result = morphism(schema, source, Destination);
183+
result.forEach((item, idx) => {
184+
expect(item).toEqual(expected[idx]);
185+
});
186+
});
164187
});
165188

166189
describe('Morphism Function Type Checking', () => {

0 commit comments

Comments
 (0)