Skip to content

Commit

Permalink
feat(constructSignature): add construct signature (#116)
Browse files Browse the repository at this point in the history
* feat(constructSignature): add construct signature

* remove commented code

* use const instead of let

* divide two cases for call and construct signature in the switch
  • Loading branch information
Pmyl authored Dec 3, 2019
1 parent 8f26218 commit b0aa18a
Show file tree
Hide file tree
Showing 5 changed files with 90 additions and 2 deletions.
22 changes: 22 additions & 0 deletions docs/DETAILS.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,28 @@ const mock = createMock<Person>();
mock() // 0
mock.name // ""

```
## Interfaces with construct signatures
For overload constructors it will use the first one
```ts
interface PersonWithHat {
hatSize: number;
}

interface PersonWithoutHat {
shirtSize: number;
}

interface Person {
new (hatSize: number): PersonWithHat
new (): PersonWithoutHat
name: string
}

const mock = createMock<Person>();
new mock() // { hatSize: 0 }
mock.name // ""

```
## Classes
```ts
Expand Down
2 changes: 2 additions & 0 deletions src/transformer/descriptor/descriptor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,8 @@ export function GetDescriptor(node: ts.Node, scope: Scope): ts.Expression {
return GetMethodDeclarationDescriptor(node as ts.MethodDeclaration, scope);
case ts.SyntaxKind.FunctionType:
return GetFunctionTypeDescriptor(node as ts.FunctionTypeNode, scope);
case ts.SyntaxKind.ConstructSignature:
return GetFunctionTypeDescriptor(node as ts.ConstructSignatureDeclaration, scope);
case ts.SyntaxKind.CallSignature:
return GetFunctionTypeDescriptor(node as ts.CallSignatureDeclaration, scope);
case ts.SyntaxKind.ArrowFunction:
Expand Down
2 changes: 1 addition & 1 deletion src/transformer/descriptor/method/functionType.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { GetDescriptor } from '../descriptor';
import { PropertySignatureCache } from '../property/cache';
import { GetMethodDescriptor } from './method';

export function GetFunctionTypeDescriptor(node: ts.FunctionTypeNode | ts.CallSignatureDeclaration, scope: Scope): ts.Expression {
export function GetFunctionTypeDescriptor(node: ts.FunctionTypeNode | ts.CallSignatureDeclaration | ts.ConstructSignatureDeclaration, scope: Scope): ts.Expression {
const property: ts.PropertyName = PropertySignatureCache.instance.get();

const returnValue: ts.Expression = GetDescriptor(node.type, scope);
Expand Down
4 changes: 3 additions & 1 deletion src/transformer/descriptor/properties/properties.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,9 @@ export function GetProperties(node: ts.Node, scope: Scope): ts.Expression {
const type: ts.Type = typeChecker.getTypeAtLocation(node);
const symbols: ts.Symbol[] = typeChecker.getPropertiesOfType(type);

const signatures: ReadonlyArray<ts.Signature> = typeChecker.getSignaturesOfType(type, SignatureKind.Call);
const signatures: Array<ts.Signature> = [];
Array.prototype.push.apply(signatures, typeChecker.getSignaturesOfType(type, SignatureKind.Call));
Array.prototype.push.apply(signatures, typeChecker.getSignaturesOfType(type, SignatureKind.Construct));

return GetMockPropertiesFromSymbol(symbols, signatures, scope);
}
62 changes: 62 additions & 0 deletions test/transformer/descriptor/methods/methods.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,68 @@ describe('for methods', () => {
});
});

describe('for interface construct signature', () => {
interface InterfaceWithConstructSignature {
new (a: number): { a: number };
b: string;
}

interface InterfaceWithConstructSignatureReturn {
new (a: number): InterfaceWithConstructSignature;
b: string;
}

interface InterfaceWithConstructSignatureOverload {
new (a: number): { a: number };
new (b: string): { b: string };
new (): { c: Date };
}

it('should set the constructor and properties', () => {
const properties: InterfaceWithConstructSignature = createMock<InterfaceWithConstructSignature>();
expect(new properties(2).a).toBe(0);
expect(properties.b).toBe('');
});

it('should set the constructor with return value constructor', () => {
const properties: InterfaceWithConstructSignatureReturn = createMock<InterfaceWithConstructSignatureReturn>();
expect(new (new properties(2))(2).a).toBe(0);
expect(new properties(2).b).toBe('');
expect(properties.b).toBe('');
});

it('should use the first overload if any', () => {
const properties: InterfaceWithConstructSignatureOverload = createMock<InterfaceWithConstructSignatureOverload>();
//tslint:disable-next-line
expect((new properties() as any).a).toBe(0);
});
});

describe('for interface construct signature', () => {
interface InterfaceWithCallSignature {
new (a: number): { a: number };
b: string;
}

interface InterfaceWithCallSignatureReturn {
new (a: number): InterfaceWithCallSignature;
b: string;
}

it('should set the constructor and properties', () => {
const properties: InterfaceWithCallSignature = createMock<InterfaceWithCallSignature>();
expect(new properties(2).a).toBe(0);
expect(properties.b).toBe('');
});

it('should set the constructor with return value constructor', () => {
const properties: InterfaceWithCallSignatureReturn = createMock<InterfaceWithCallSignatureReturn>();
expect(new (new properties(2))(2).a).toBe(0);
expect(new properties(2).b).toBe('');
expect(properties.b).toBe('');
});
});

describe('for declaration', () => {
class MyClass {
public method(): number {
Expand Down

0 comments on commit b0aa18a

Please sign in to comment.