Reputation: 39514
I have the following C# class:
public class Envelope<T> {
public List<Error> Errors { get; private set; } = new List<Error>();
public Paging Paging { get; private set; }
public List<T> Result { get; private set; } = new List<T>();
public Envelope(T result) : this(new List<T> { result }, null, new List<Error>()) { }
public Envelope(List<T> result) : this (result, null, new List<Error>()) { }
public Envelope(List<Error> errors) : this(new List<T>(), null, errors) { }
public Envelope(List<T> result, Paging paging, List<Error> errors) {
Errors = errors;
Paging = paging;
Result = result;
}
}
I need to convert this class to TypeScript on an Angular 6 project so I did:
export class Envelope<T> {
errors: Error[];
paging: Paging;
result: T[];
constructor(result: T[], paging: Paging, errors: Error[]) {
this.errors = errors;
this.paging = paging;
this.result = result;
}
}
The problem is that Typescript does not allow more than one constructor so replicating the quite different constructors I have in C# seems impossible.
Is there a way to do this?
Should Envelope be an interface in TypeScript?
Basically Envelope is a Wrapper for an API response to contain various objecs such as the Result itself, Paging and List of possible errors.
Upvotes: 0
Views: 1251
Reputation:
Given your code, this should work and seems waaaay simpler :
export class Envelope<T> {
constructor(
public result?: T[],
public paging?: Paging,
public errors: Error[] = null
) {}
}
You have shorthands :
?
after a member name renders it optional, meaning that if you don't provide it, you'll simply have undefined
in place of it's value. As a side note, Typescript allow several constructors in a ... strange way :
export class Envelope<T> {
constructor(public result: T[])
constructor(public paging: Paging)
constructor(public errors: Error[])
// ...
{}
}
The issue with this syntax is that you will have to test every paramter with instanceof
to see if they're of the expected type, which I don't particularily like (optional parameters seems simpler to me)
Upvotes: 3
Reputation: 250366
You can create constructor overloads, but you have to distinguish between them manually in the implementation. In your case, the first argument for the implementation would be a union of T| T[] | Error[]
and you can use type guards to manually differentiate between the cases in the union:
function isErrorArray<T>(e: T | Error[]): e is Error[] {
return e instanceof Array && e[0] && e[0] instanceof Error;
}
export class Envelope<T> {
errors: Error[];
paging: Paging;
result: T[];
constructor(result: T)
constructor(errors: Error[])
constructor(result: T[], paging: Paging, errors: Error[])
constructor(result: T | T[] | Error[], paging?: Paging, errors?: Error[]) {
if (isErrorArray(result)) {
errors = result;
result = [] as T[];
}
if (Array.isArray(result)) {
} else {
result = [result];
}
this.errors = errors;
this.paging = paging;
this.result = result; // result will be T[] because of the above ifs
}
}
Upvotes: 4