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