Skip to content

Commit

Permalink
fix: Fix generic type parameter should be optional on derived class (#…
Browse files Browse the repository at this point in the history
  • Loading branch information
ktutnik committed Apr 26, 2021
1 parent 9cdb11b commit 8eb2132
Show file tree
Hide file tree
Showing 3 changed files with 104 additions and 9 deletions.
17 changes: 10 additions & 7 deletions packages/reflect/src/decorators.ts
Original file line number Diff line number Diff line change
Expand Up @@ -197,9 +197,14 @@ export namespace generic {
if (type === decorator.target) return []
return [...getParent(parent), type]
}
const getTemplate = (target: Class) => getMetadata(target)
.find((x: GenericTypeParameterDecorator): x is GenericTypeParameterDecorator => x.kind === "GenericTemplate")

const getTemplate = (target: Class): GenericTypeParameterDecorator | undefined => {
const meta = getMetadata(target)
.find((x: GenericTypeParameterDecorator): x is GenericTypeParameterDecorator => x.kind === "GenericTemplate")
if (meta) return meta
// if not found walk through the parent to get the parameter decorator
const parent: Class = Object.getPrototypeOf(target)
return parent.prototype ? getTemplate(parent) : undefined
}
if (typeTarget === decorator.target) return
if (!(typeTarget.prototype instanceof decorator.target))
throw new Error(`Unable to get type information because ${typeTarget.name} is not inherited from ${decorator.target.name}`)
Expand Down Expand Up @@ -235,10 +240,8 @@ export namespace generic {
}
// continue searching other template
const templates = getTemplate(type)
if (templates) {
tmpType = type
templateDec = templates
}
tmpType = type
templateDec = templates!
}
}

Expand Down
80 changes: 80 additions & 0 deletions tests/behavior/reflect/__snapshots__/generic-types.spec.ts.snap
Original file line number Diff line number Diff line change
Expand Up @@ -1587,6 +1587,86 @@ Object {
}
`;

exports[`Generic Should able to omit generic parameter even if used on derived class 1`] = `
Object {
"ctor": Object {
"kind": "Constructor",
"name": "constructor",
"parameters": Array [],
},
"decorators": Array [
Object {
"kind": "GenericType",
"target": MyClass,
"types": Array [
String,
],
Symbol(tinspector:decoratorId): Symbol(genericType),
Symbol(tinspector:decoratorOption): Object {
"allowMultiple": false,
"applyTo": Array [],
"inherit": false,
"removeApplied": true,
},
},
],
"kind": "Class",
"methods": Array [
Object {
"decorators": Array [
Object {
"genericArguments": Array [],
"kind": "Override",
"target": GrandSuperClass,
"type": "T",
Symbol(tinspector:decoratorId): Symbol(override),
Symbol(tinspector:decoratorOption): Object {
"allowMultiple": false,
"applyTo": Array [],
"inherit": true,
"removeApplied": true,
},
},
],
"kind": "Method",
"name": "method",
"parameters": Array [],
"returnType": String,
"typeClassification": "Primitive",
},
],
"name": "MyClass",
"properties": Array [
Object {
"decorators": Array [
Object {
"genericArguments": Array [],
"kind": "Override",
"target": SuperClass,
"type": "T",
Symbol(tinspector:decoratorId): Symbol(override),
Symbol(tinspector:decoratorOption): Object {
"allowMultiple": false,
"applyTo": Array [],
"inherit": true,
"removeApplied": true,
},
},
],
"get": undefined,
"kind": "Property",
"name": "property",
"set": undefined,
"type": String,
"typeClassification": "Primitive",
},
],
"super": SuperClass,
"type": MyClass,
"typeClassification": "Class",
}
`;

exports[`Generic Should inherit generic data type when overridden 1`] = `
Array [
Object {
Expand Down
16 changes: 14 additions & 2 deletions tests/behavior/reflect/generic-types.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -172,9 +172,21 @@ describe("Generic", () => {
@type("T")
method(): T { return {} as any }
}

class SuperClass<T> extends GrandSuperClass<T> { }

@generic.argument(String)
class MyClass extends SuperClass<string>{ }
expect(reflect(MyClass)).toMatchSnapshot()
})
it("Should able to omit generic parameter even if used on derived class", () => {
@generic.parameter("T")
class GrandSuperClass<T> {
@type("T")
method(): T { return {} as any }
}
class SuperClass<T> extends GrandSuperClass<T> {
@type("T")
property:T
}
@generic.argument(String)
class MyClass extends SuperClass<string>{ }
expect(reflect(MyClass)).toMatchSnapshot()
Expand Down

0 comments on commit 8eb2132

Please sign in to comment.