type TupleOf = N extends N ? number extends N ? T[] : _TupleOf : never type _TupleOf = R['length'] extends N ? R : _TupleOf export class Vector { public readonly values: TupleOf constructor( public readonly length: N ) { this.values = Array(length).fill(0) as TupleOf } } export class Matrix { public readonly values: TupleOf, R> constructor( public readonly rows: R, public readonly cols: C, ) { this.values = Array(rows).fill(0).map(() => Array(cols).fill(0) as TupleOf) as TupleOf, R> } isSquare() { return Number(this.rows) === Number(this.cols) } set(row: number, col: number, value: number) { this.validateCoordinates(row, col) this.values[row-1 as R][col-1 as C] = value } get(row: number, col: number): number { this.validateCoordinates(row, col) return this.values[row-1 as R][col-1 as C] as number } getDeterminant() { if ( !this.isSquare() ) { throw new RangeError('Cannot find determinant of non-square matrix.') } const determinant = (m: number[][]): number => m.length == 1 ? m[0][0] : m.length == 2 ? m[0][0]*m[1][1]-m[0][1]*m[1][0] : m[0].reduce((r,e,i) => r+(-1)**(i+2)*e*determinant(m.slice(1).map(c => c.filter((_,j) => i != j))),0) return determinant(this.values) } protected validateCoordinates(row: number, col: number) { if ( row < 1 || row > Number(this.rows) || col < 1 || col > Number(this.cols) ) { throw new RangeError('Invalid matrix coordinates') } } }