Remove the need to self-reference Form['lines'] in Form subclasses.
authorRobert Sesek <rsesek@bluestatic.org>
Sun, 18 Oct 2020 06:12:59 +0000 (02:12 -0400)
committerRobert Sesek <rsesek@bluestatic.org>
Sun, 18 Oct 2020 06:12:59 +0000 (02:12 -0400)
This self-reference is not supported in TypeSciprt 4 (see
https://github.com/microsoft/TypeScript/issues/40315), and it is
unnecessary.

25 files changed:
src/core/Form.test.ts
src/core/Form.ts
src/core/Line.test.ts
src/core/Line.ts
src/core/TaxReturn.test.ts
src/core/TaxReturn.ts
src/core/Trace.test.ts
src/fed2019/Form1040.ts
src/fed2019/Form1099B.ts
src/fed2019/Form1099DIV.ts
src/fed2019/Form1099INT.ts
src/fed2019/Form1099R.ts
src/fed2019/Form1116.ts
src/fed2019/Form6251.ts
src/fed2019/Form8606.ts
src/fed2019/Form8949.ts
src/fed2019/Form8959.ts
src/fed2019/Form8960.ts
src/fed2019/Form8995.ts
src/fed2019/Schedule1.ts
src/fed2019/Schedule2.ts
src/fed2019/Schedule3.ts
src/fed2019/ScheduleA.ts
src/fed2019/ScheduleD.ts
src/fed2019/W2.ts

index 8098759d92cc423dbb05373410fbe00742d41fd2..4178d1930f11e37ed665c222e1f52e92a3f77ebd 100644 (file)
@@ -16,7 +16,7 @@ class TestTaxReturn extends TaxReturn {
 test('add and get line', () => {
   const l = new ComputedLine<number>(() => 42);
 
-  class TestForm extends Form<TestForm['lines']> {
+  class TestForm extends Form {
     readonly name = 'Test Form';
 
     readonly lines = { '1': l };
@@ -27,13 +27,13 @@ test('add and get line', () => {
 });
 
 test('get non-existent line', () => {
-  class TestForm extends Form<TestForm['lines']> {
+  class TestForm extends Form {
     readonly name = 'Test';
     readonly lines = {};
   };
 
   const f = new TestForm();
-  const fAsAny: Form<any> = f;
+  const fAsAny: Form = f;
   expect(() => fAsAny.getLine('line')).toThrow(NotFoundError);
 
   //TYPEERROR:
@@ -45,7 +45,7 @@ test('input', () => {
     filingStatus: string;
     money: number;
   };
-  class TestForm extends Form<any, TestInput> {
+  class TestForm extends Form<TestInput> {
     readonly name = '1040';
 
     readonly lines = null;
@@ -56,7 +56,7 @@ test('input', () => {
 });
 
 test('get value', () => {
-  class TestForm extends Form<TestForm['lines']> {
+  class TestForm extends Form {
     readonly name = 'Form';
 
     readonly lines = {
@@ -71,18 +71,18 @@ test('get value', () => {
   //TYPEERROR:
   //let s: string = f.getValue(tr, 'line');
 
-  const fAsAny: Form<any> = f;
+  const fAsAny: Form = f;
   expect(() => fAsAny.getValue(tr, 'other')).toThrow(NotFoundError);
   //TYPEERROR:
   //expect(() => f.getValue(tr, 'other')).toThrow(NotFoundError);
 });
 
 test('form types', () => {
-  class FormA extends Form<any> {
+  class FormA extends Form {
     readonly name = 'A';
     readonly lines = {};
   };
-  class FormB extends Form<any> {
+  class FormB extends Form {
     readonly name = 'B';
     readonly lines = {};
   };
index c713f170ed3ececc344cf7c6eb0f21e59e9e9447..dc7e70ac0353f355dee4de6b7fca44e714e9fdc9 100644 (file)
@@ -9,11 +9,10 @@ import * as Trace from './Trace';
 import { Line } from './Line';
 import { InconsistencyError, NotFoundError } from './Errors';
 
-export default abstract class Form<L extends { [key: string]: Line<any> },
-                                   I = unknown> {
+export default abstract class Form<I = unknown> {
   abstract readonly name: string;
 
-  abstract readonly lines: L;
+  abstract readonly lines: { [key: string]: Line<any> };
 
   readonly supportsMultipleCopies: boolean = false;
 
@@ -35,14 +34,17 @@ export default abstract class Form<L extends { [key: string]: Line<any> },
     return undefined;
   }
 
-  getLine<K extends keyof L>(id: K): L[K] {
+  getLine<K extends keyof this['lines']>(id: K): this['lines'][K] {
     if (!(id in this.lines))
       throw new NotFoundError(`Form ${this.name} does not have line ${id}`);
-    return this.lines[id];
+    // This coercion is safe: the method's generic constraint for K ensures
+    // a valid key in |lines|, and the abstract declaration of |lines| ensures
+    // the correct index type.
+    return this.lines[id as any] as this['lines'][K];
   }
 
-  getValue<K extends keyof L>(tr: TaxReturn, id: K): ReturnType<L[K]['value']> {
-    const line: L[K] = this.getLine(id);
+  getValue<K extends keyof this['lines']>(tr: TaxReturn, id: K): ReturnType<this['lines'][K]['value']> {
+    const line = this.getLine(id);
     return line.value(tr);
   }
 
@@ -59,10 +61,10 @@ export default abstract class Form<L extends { [key: string]: Line<any> },
   }
 };
 
-export type FormClass<T extends Form<any>> = new (...args: any[]) => T;
+export type FormClass<T extends Form> = new (...args: any[]) => T;
 
-export function isFormT<T extends Form<any>>(form: Form<any>,
-                                             formClass: FormClass<T>):
-                                                form is T {
+export function isFormT<T extends Form>(form: Form,
+                                        formClass: FormClass<T>):
+                                            form is T {
   return form.constructor === formClass;
 }
index 27ec6a313f71f47dfa259f789607fe7498c5ff74..4a596389171f15c49aa0bd57068a2998619e7450 100644 (file)
@@ -39,7 +39,7 @@ test('computed line', () => {
 });
 
 test('reference line', () => {
-  class TestForm extends Form<TestForm['lines']> {
+  class TestForm extends Form {
     readonly name = 'Form 1';
     readonly lines = {
       '6b': new ConstantLine(12.34),
@@ -65,18 +65,18 @@ test('reference line', () => {
 });
 
 test('self reference line', () => {
-  class OtherForm extends Form<OtherForm['lines']> {
+  class OtherForm extends Form {
     readonly name = 'Form A';
     readonly lines = {
       '6c': new ConstantLine(55)
     };
   };
-  class TestForm extends Form<TestForm['lines']> {
+  class TestForm extends Form {
     readonly name = 'Form 1';
     readonly lines = {
       'a': new ConstantLine(100.2),
       'b': new ReferenceLine(OtherForm, '6c'),
-      'c': new ReferenceLine((TestForm as unknown) as FormClass<Form<any>>, 'b'),
+      'c': new ReferenceLine((TestForm as unknown) as FormClass<Form>, 'b'),
       'd': new ReferenceLine(TestForm as any, 'b'),
     };
   };
@@ -97,7 +97,7 @@ test('input line', () => {
     key: string;
     key2?: string;
   }
-  class TestForm extends Form<TestForm['lines'], Input> {
+  class TestForm extends Form<Input> {
     readonly name = 'F1';
     readonly lines = {
       '1': new InputLine<Input>('key'),
@@ -119,14 +119,14 @@ test('input line', () => {
 });
 
 test('line stack', () => {
-  class FormZ extends Form<FormZ['lines'], {'input': number}> {
+  class FormZ extends Form<{'input': number}> {
     readonly name = 'Z';
     readonly lines = {
       '3': new InputLine<any, any>('input')
     }
   };
 
-  class FormZ2 extends Form<FormZ2['lines']> {
+  class FormZ2 extends Form {
     readonly name = 'Z-2';
     readonly lines = {
       '2c': new ComputedLine<number>((tr: TaxReturn): any => {
@@ -144,7 +144,7 @@ test('line stack', () => {
 });
 
 test('accumulator line', () => {
-  class TestForm extends Form<TestForm['lines']> {
+  class TestForm extends Form {
     readonly name = 'Form B';
     readonly supportsMultipleCopies = true;
     readonly lines = {
index 8995beee8f1545ccf85e5c69ddd957140b5da987..821483f1e9a4608f33e37e6edcc60920c9d2b2f9 100644 (file)
@@ -11,7 +11,7 @@ export abstract class Line<T> {
   private _description?: string;
 
   _id: string;  // _id is set by Form.init().
-  form: Form<any, any>;  // Set by Form.init();
+  form: Form;  // Set by Form.init();
 
   constructor(description?: string) {
     this._description = description;
@@ -46,7 +46,7 @@ export class ComputedLine<T> extends Line<T> {
   }
 };
 
-export class ReferenceLine<F extends Form<any>,
+export class ReferenceLine<F extends Form,
                            L extends keyof F['lines'],
                            T extends ReturnType<F['lines'][L]['value']>>
                                extends Line<T> {
@@ -81,7 +81,7 @@ export class InputLine<U = unknown, T extends keyof U = any> extends Line<U[T]>
   private _input: T;
   private _fallback: U[T];
 
-  form: Form<any, U>;
+  form: Form<U>;
 
   constructor(input: T, description?: string, fallback?: U[T]) {
     super(description || `Input from ${input}`);
@@ -101,7 +101,7 @@ export class InputLine<U = unknown, T extends keyof U = any> extends Line<U[T]>
   }
 };
 
-export class AccumulatorLine<F extends Form<any>,
+export class AccumulatorLine<F extends Form,
                              L extends keyof F['lines']>
                                  extends Line<number> {
   private _form: FormClass<F>;
@@ -133,13 +133,13 @@ export class UnsupportedLine extends Line<number> {
   }
 };
 
-export function sumLineOfForms<F extends Form<any>, L extends keyof F['lines']>(
+export function sumLineOfForms<F extends Form, L extends keyof F['lines']>(
     tr: TaxReturn, forms: F[], line: L): number {
   const reducer = (acc: number, curr: F) => acc + curr.getValue(tr, line);
   return forms.reduce(reducer, 0);
 }
 
-export function sumFormLines<F extends Form<any>, L extends keyof F['lines']>(
+export function sumFormLines<F extends Form, L extends keyof F['lines']>(
     tr: TaxReturn, form: F, lines: L[]): number {
   let value = 0;
   for (const line of lines)
index 4da4fcb123260bd0b991d9ad4db93a253a2adc16..664e529c9d78fad1c89d462eec8fda9ee56146cd 100644 (file)
@@ -59,7 +59,7 @@ test('get non-existent person', () => {
 });
 
 test('single-copy forms', () => {
-  class TestForm extends Form<null> {
+  class TestForm extends Form {
     readonly name = 'Test Form';
     readonly lines = null;
   };
@@ -73,7 +73,7 @@ test('single-copy forms', () => {
 });
 
 test('multiple-copy forms', () => {
-  class TestForm extends Form<null> {
+  class TestForm extends Form {
     readonly name = 'Test Form';
     readonly supportsMultipleCopies = true;
     readonly lines = null;
@@ -97,7 +97,7 @@ test('multiple-copy forms', () => {
 });
 
 test('get non-existent form', () => {
-  class TestForm extends Form<null> {
+  class TestForm extends Form {
     readonly name = 'Test Form';
     readonly lines = null;
   }
@@ -107,7 +107,7 @@ test('get non-existent form', () => {
   expect(tr.findForms(TestForm)).toEqual([]);
 });
 
-class PerPersonForm extends Form<PerPersonForm['lines']> {
+class PerPersonForm extends Form {
   private _person?: Person;
 
   readonly name = 'Per Person';
index cce8132512131cf2987d2e380c8587398e65161e..ccd9ee85ffbfae5759bc63608f620bdbfa6e6e91 100644 (file)
@@ -9,13 +9,13 @@ import { NotFoundError, InconsistencyError, UnsupportedFeatureError } from './Er
 
 export default abstract class TaxReturn {
   private _people: Person[] = [];
-  private _forms: Form<any, unknown>[] = [];
+  private _forms: Form[] = [];
 
   abstract get year(): number;
 
   abstract get includeJointPersonForms(): boolean;
 
-  get forms(): Form<any, unknown>[] {
+  get forms(): Form[] {
     return [...this._forms];
   }
 
@@ -40,9 +40,9 @@ export default abstract class TaxReturn {
     return people[0];
   }
 
-  addForm(form: Form<any>) {
+  addForm(form: Form) {
     if (!form.supportsMultipleCopies) {
-      const other = this.findForms(form.constructor as FormClass<Form<any>>);
+      const other = this.findForms(form.constructor as FormClass<Form>);
       if (other.length > 0) {
         throw new InconsistencyError(`Cannot have more than one type of form ${form.name}`);
       }
@@ -51,7 +51,7 @@ export default abstract class TaxReturn {
     this._forms.push(form);
   }
 
-  findForm<T extends Form<any>>(cls: FormClass<T>): T | null {
+  findForm<T extends Form>(cls: FormClass<T>): T | null {
     const forms = this.findForms(cls);
     if (forms.length == 0)
       return null;
@@ -60,9 +60,9 @@ export default abstract class TaxReturn {
     return forms[0];
   }
 
-  findForms<T extends Form<any>>(cls: FormClass<T>): T[] {
+  findForms<T extends Form>(cls: FormClass<T>): T[] {
     const forms: T[] = this._forms
-        .filter((form: Form<any>): form is T => isFormT(form, cls))
+        .filter((form: Form): form is T => isFormT(form, cls))
         .filter((form: T) => {
           const person = form.person();
           if (person === undefined)
@@ -76,7 +76,7 @@ export default abstract class TaxReturn {
     return forms;
   }
 
-  getForm<T extends Form<any>>(cls: FormClass<T>): T {
+  getForm<T extends Form>(cls: FormClass<T>): T {
     const form = this.findForm(cls);
     if (!form)
       throw new NotFoundError(`No form ${cls.name}`);
index 1bdf55b3902aed4476bab29bd2046660a310be62..75130cb056be9002b9205a162d88db10ad36ef40 100644 (file)
@@ -19,7 +19,7 @@ interface Input {
   value: number;
 };
 
-class TestForm extends Form<TestForm['lines'], Input> {
+class TestForm extends Form<Input> {
   readonly name = 'TF';
 
   readonly lines = {
index 579e8eb7331347bf2ba1b02df62d2d4c180c8118..edcfb110bbed11d643841add1f8dea3d3ad1f114 100644 (file)
@@ -31,7 +31,7 @@ export interface Form1040Input {
   filingStatus: FilingStatus;
 };
 
-export default class Form1040 extends Form<Form1040['lines'], Form1040Input> {
+export default class Form1040 extends Form<Form1040Input> {
   readonly name = '1040';
 
   readonly lines = {
@@ -146,7 +146,7 @@ export default class Form1040 extends Form<Form1040['lines'], Form1040Input> {
     '13a': new UnsupportedLine('Child tax credit'),
 
     '13b': new ComputedLine((tr): number => {
-      let value  = this.getValue(tr, '13a');
+      let value: number = this.getValue(tr, '13a');
       const sched3 = tr.findForm(Schedule3);
       if (sched3)
         value += undefinedToZero(sched3.getValue(tr, '7'));
@@ -253,7 +253,7 @@ export function computeTax(income: number, filingStatus: FilingStatus): number {
   return ((income - bracketStart) * bracket[1]) + bracket[2];
 };
 
-export class QDCGTaxWorksheet extends Form<QDCGTaxWorksheet['lines']> {
+export class QDCGTaxWorksheet extends Form {
   readonly name = 'QDCG Tax Worksheet';
 
   readonly lines = {
index 67a41a39152602100de6c343aca883ad8b9022ff..e4f3680b9e55a5ebb99bbe46f333798d0612ac76 100644 (file)
@@ -36,7 +36,7 @@ export interface Form1099BInput {
 
 class Input<T extends keyof Form1099BInput> extends InputLine<Form1099BInput, T> {};
 
-export default class Form1099B extends Form<Form1099B['lines'], Form1099BInput> {
+export default class Form1099B extends Form<Form1099BInput> {
   readonly name = '1099-B';
 
   readonly supportsMultipleCopies = true;
index dc004767f76a7a0958bfd5ad2c59907278b9cb7b..d2490110a7acdda4ca097cc749c29987114c907a 100644 (file)
@@ -29,7 +29,7 @@ export interface Form1099DIVInput {
 
 class Input<T extends keyof Form1099DIVInput> extends InputLine<Form1099DIVInput, T> {};
 
-export default class Form1099DIV extends Form<Form1099DIV['lines'], Form1099DIVInput> {
+export default class Form1099DIV extends Form<Form1099DIVInput> {
   readonly name = '1099-DIV';
 
   readonly supportsMultipleCopies = true;
index b038f998db471355c3b3410ef858469a4bf55cd4..33a8a6a2bc618bcbac66835e0d972784f931a050 100644 (file)
@@ -26,7 +26,7 @@ export interface Form1099INTInput {
 
 class Input<T extends keyof Form1099INTInput> extends InputLine<Form1099INTInput, T> {};
 
-export default class Form1099INT extends Form<Form1099INT['lines'], Form1099INTInput> {
+export default class Form1099INT extends Form<Form1099INTInput> {
   readonly name = '1099-INT';
 
   readonly supportsMultipleCopies = true;
index 744741afc10c99190cf942aeaef45af41675b026..c79be514fa0032b91bd8dd2aa4aadf2dcb1fbc91 100644 (file)
@@ -54,7 +54,7 @@ export interface Form1099RInput {
 
 class Input<T extends keyof Form1099RInput> extends InputLine<Form1099RInput, T> {};
 
-export default class Form1099R extends Form<Form1099R['lines'], Form1099RInput> {
+export default class Form1099R extends Form<Form1099RInput> {
   readonly name = '1099-R';
 
   readonly supportsMultipleCopies = true;
index 61cc81bf47101e75afa47ebc395952da46e1b3dc..d5dcdfd542f511ff20ebb25d6cf8c6242d42ccc7 100644 (file)
@@ -34,7 +34,7 @@ export interface Form1116Input {
 
 class Input<T extends keyof Form1116Input> extends InputLine<Form1116Input, T> {};
 
-export default class Form1116 extends Form<Form1116['lines'], Form1116Input> {
+export default class Form1116 extends Form<Form1116Input> {
   readonly name = '1116';
 
   readonly lines = {
index af663cc72972918b69355487251f2f2840bef866..2dab2577cf87b7ff251887486bbd407313ef435f 100644 (file)
@@ -14,7 +14,7 @@ import Schedule2 from './Schedule2';
 import Schedule3 from './Schedule3';
 import ScheduleD, { ScheduleDTaxWorksheet } from './ScheduleD';
 
-export default class Form6251 extends Form<Form6251['lines']> {
+export default class Form6251 extends Form {
   readonly name = '6251';
 
   readonly lines = {
index 7d8d4b5e35bf95fb4c03d924b4325f4fe62e4f2b..4938de3411401990669c8a2859c8ce5f52cae4e9 100644 (file)
@@ -20,7 +20,7 @@ export interface Form8606Input {
 
 class Input<T extends keyof Form8606Input> extends InputLine<Form8606Input, T> {};
 
-export default class Form8606 extends Form<Form8606['lines'], Form8606Input> {
+export default class Form8606 extends Form<Form8606Input> {
   readonly name = '8606';
 
   readonly supportsMultipleCopies = true;
index 51bd2912ed425874d67d35fb6ff0aac5f0b6c411..67e0ab6a972a9caeb8bf89a7a606e3e53f2154f7 100644 (file)
@@ -76,7 +76,7 @@ class Form8949Line extends Line<Form8949Total> {
   }
 };
 
-export default class Form8949 extends Form<Form8949['lines']> {
+export default class Form8949 extends Form {
   readonly name = '8949';
 
   readonly supportsMultipleCopies = true;
index a4ebc9f9bec9c6780ccb860cbd25275a6af5051f..0aef950b362c0b7078df3b0d571612b81bfe43ad 100644 (file)
@@ -10,7 +10,7 @@ import { clampToZero } from '../core/Math';
 import Form1040, { FilingStatus } from './Form1040';
 import W2 from './W2';
 
-export default class Form8959 extends Form<Form8959['lines']> {
+export default class Form8959 extends Form {
   readonly name = '8959';
 
   readonly lines = {
index 724303ec7ebc9c4b020df0d1eef0caf36ba75969..359138998cb0e0a7077df1f3f1677ec257fa3f2a 100644 (file)
@@ -10,7 +10,7 @@ import { clampToZero, undefinedToZero } from '../core/Math';
 import Form1040, { FilingStatus } from './Form1040';
 import Schedule1 from './Schedule1';
 
-export default class Form8960 extends Form<Form8960['lines']> {
+export default class Form8960 extends Form {
   readonly name = '8960';
 
   readonly lines = {
index 52bcbb9420293e2a20fae50eabca00187dd7c149..1590fb7d7d36cef298d969a64496a55fd5c467da 100644 (file)
@@ -18,7 +18,7 @@ export interface Form8995REITInput {
 // Dividends from REITs get preferential tax treatment, but the form used to
 // calculate that differs based off taxable income amounts. But the QBI
 // computation for RETIs is the same. This just models the REIT portion.
-export default class Form8995REIT extends Form<Form8995REIT['lines']> {
+export default class Form8995REIT extends Form {
   readonly name = '8995 REIT';
 
   // This uses line numbers from 8995-A.
index ef6707c0dabf5108d93e0cd9edba9873f177611b..a7a4fe46d18e634b6f4be39061c428037c36bffc 100644 (file)
@@ -58,7 +58,7 @@ class Input<T extends keyof Schedule1Input> extends InputLine<Schedule1Input, T>
   }
 };
 
-export default class Schedule1 extends Form<Schedule1['lines'], Schedule1Input> {
+export default class Schedule1 extends Form<Schedule1Input> {
   readonly name = 'Schedule 1';
 
   readonly lines = {
@@ -150,7 +150,7 @@ export interface SALTWorksheetInput {
   prevYearFilingStatus?: FilingStatus;
 };
 
-export class SALTWorksheet extends Form<SALTWorksheet['lines'], SALTWorksheetInput> {
+export class SALTWorksheet extends Form<SALTWorksheetInput> {
   readonly name = 'SALT Refund Worksheet';
 
   readonly lines = {
index 87e28194826e0bded445956b14707a2aa1f8b294..20e42a45551e481299a6aa88a3295e0cde7df9f1 100644 (file)
@@ -14,7 +14,7 @@ import Form6251 from './Form6251';
 import Form8959 from './Form8959';
 import Form8960 from './Form8960';
 
-export default class Schedule2 extends Form<Schedule2['lines']> {
+export default class Schedule2 extends Form {
   readonly name = 'Schedule 2';
 
   readonly lines = {
index 055728868f10ec27a703118271902edaeab63faa..776f1bae7cbc59588a2d44da4178fbbc25b66f58 100644 (file)
@@ -17,7 +17,7 @@ export interface Schedule3Input {
   estimatedTaxPayments?: number;
 };
 
-export default class Schedule3 extends Form<Schedule3['lines'], Schedule3Input> {
+export default class Schedule3 extends Form<Schedule3Input> {
   readonly name = 'Schedule 3';
 
   readonly lines = {
index 8331a6252b2b63dcdb47998b6d92b969a88ce887..acb49cdea13842f266ce159da9ba5b1d99f8cadf 100644 (file)
@@ -34,7 +34,7 @@ export interface ScheduleAInput {
 
 class Input extends InputLine<ScheduleAInput> {};
 
-export default class ScheduleA extends Form<ScheduleA['lines'], ScheduleAInput> {
+export default class ScheduleA extends Form<ScheduleAInput> {
   readonly name = 'Schedule A';
 
   readonly lines = {
index 0925dc9e97fa5817ed9f4218389d0135589eddf1..e46f21bb3c340e55c6dabac9ad7b851f0795e8e9 100644 (file)
@@ -12,7 +12,7 @@ import Form8949, { Form8949Box } from './Form8949';
 import Form1099DIV from './Form1099DIV';
 import Form1040, { FilingStatus, QDCGTaxWorksheet, computeTax } from './Form1040';
 
-export default class ScheduleD extends Form<ScheduleD['lines']> {
+export default class ScheduleD extends Form {
   readonly name = 'Schedule D';
 
   readonly lines = {
@@ -85,7 +85,7 @@ export default class ScheduleD extends Form<ScheduleD['lines']> {
   };
 };
 
-export class ScheduleDTaxWorksheet extends Form<ScheduleDTaxWorksheet['lines']> {
+export class ScheduleDTaxWorksheet extends Form {
   readonly name = 'Schedule D Tax Worksheet';
 
   readonly lines = {
index a0f7fffd50bca895aad31f455ea4861d681ff20c..f4ba24ea2f4b176bede6d9517d260e72df20e088 100644 (file)
@@ -37,7 +37,7 @@ export interface W2Input {
 
 class Input<T extends keyof W2Input> extends InputLine<W2Input, T> {};
 
-export default class W2 extends Form<W2['lines'], W2Input> {
+export default class W2 extends Form<W2Input> {
   readonly name = 'W-2';
 
   readonly supportsMultipleCopies = true;