Add the ability to filter forms by Person.
[ustaxlib.git] / src / core / Form.ts
1 import Person from './Person';
2 import TaxReturn from './TaxReturn';
3 import { Line } from './Line';
4 import { InconsistencyError, NotFoundError } from './Errors';
5
6 export default abstract class Form<L extends { [key: string]: Line<any> },
7 I = unknown> {
8 abstract readonly name: string;
9
10 protected abstract readonly _lines: L;
11
12 readonly supportsMultipleCopies: boolean = false;
13
14 private readonly _input?: I;
15
16 // Avoid using this; prefer the getLine() helpers declared below. This
17 // is only exposed for propagating line type information.
18 get lines(): L { return this._lines; }
19
20 constructor(input?: I) {
21 this._input = input;
22 }
23
24 init() {
25 for (const id in this._lines) {
26 let l = this._lines[id];
27 l._id = id;
28 l.form = this;
29 }
30 }
31
32 person(): Person | undefined {
33 return undefined;
34 }
35
36 getLine<K extends keyof L>(id: K): L[K] {
37 if (!(id in this._lines))
38 throw new NotFoundError(`Form ${this.name} does not have line ${id}`);
39 return this._lines[id];
40 }
41
42 getValue<K extends keyof L>(tr: TaxReturn, id: K): ReturnType<L[K]['value']> {
43 const line: L[K] = this.getLine(id);
44 return line.value(tr);
45 }
46
47 getInput<K extends keyof I>(name: K): I[K] {
48 if (!(name in this._input)) {
49 throw new NotFoundError(`No input with key ${name} on form ${this.name}`);
50 }
51 return this._input[name];
52 }
53
54 hasInput<K extends keyof I>(name: K): boolean {
55 return this._input !== undefined && name in this._input;
56 }
57 };
58
59 export type FormClass<T extends Form<any>> = new (...args: any[]) => T;
60
61 export function isFormT<T extends Form<any>>(form: Form<any>,
62 formClass: FormClass<T>):
63 form is T {
64 return form.constructor === formClass;
65 }