Skip to content

Commit

Permalink
♻️ refactor: Progress on enabling strict null checks.
Browse files Browse the repository at this point in the history
  • Loading branch information
make-github-pseudonymous-again committed Mar 8, 2023
1 parent 94b1d38 commit 3e6e80f
Show file tree
Hide file tree
Showing 85 changed files with 681 additions and 340 deletions.
13 changes: 8 additions & 5 deletions imports/api/appointments.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,12 @@ import {
type AppointmentFields,
} from './collection/appointments';

const sanitizeAppointmentGen = function* (
fields: Partial<AppointmentFields>,
): IterableIterator<Entry<AppointmentFields & AppointmentComputedFields>> {
const sanitizeAppointmentGen = function* (fields: {
patientId: string;
datetime?: Date;
duration?: number;
reason: string;
}): IterableIterator<Entry<AppointmentFields & AppointmentComputedFields>> {
yield* yieldKey(fields, 'patientId', String);
if (
Object.prototype.hasOwnProperty.call(fields, 'datetime') ||
Expand All @@ -32,12 +35,12 @@ const sanitizeAppointmentGen = function* (
const sanitizeAppointment = makeSanitize(sanitizeAppointmentGen);

export type AppointmentUpdate = {
patient: {
patient?: {
_id: string;
firstname?: string;
lastname?: string;
};
phone: string;
phone?: string;
datetime: Date;
duration: number;
reason: string;
Expand Down
15 changes: 10 additions & 5 deletions imports/api/consultations.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,13 @@ export const DEFAULT_DURATION_IN_SECONDS = DEFAULT_DURATION_IN_MINUTES * 60;
export const DEFAULT_DURATION_IN_MILLISECONDS =
DEFAULT_DURATION_IN_SECONDS * 1000;

export const isUnpaid = ({price = undefined, paid = undefined}) =>
paid !== price;
export const isUnpaid = ({
price = undefined,
paid = undefined,
}: {
price?: number;
paid?: number;
}) => paid !== price;

const findLastConsultationArgs = (
filter?: Filter<ConsultationDocument>,
Expand Down Expand Up @@ -161,7 +166,7 @@ export function setupConsultationsStatsPublication(collection, query) {
const [oldPrice, minRef, maxRef] = refs.get(_id);
let newPrice: number = oldPrice;
if (Object.prototype.hasOwnProperty.call(fields, 'price')) {
newPrice = fields.price;
newPrice = fields.price!;
if (oldPrice) total -= oldPrice;
if (newPrice) total += newPrice;
refs.set(_id, [newPrice, minRef, maxRef]);
Expand Down Expand Up @@ -195,10 +200,10 @@ export function setupConsultationsStatsPublication(collection, query) {
return handle;
}

const trimString = (value: string | undefined) => value?.trim();
const trimString = (value: any) => value?.trim();

const sanitizeUpdate = function* (
fields: Partial<ConsultationFields>,
fields: ConsultationFields,
): IterableIterator<Entry<ConsultationFields & ConsultationComputedFields>> {
yield* yieldKey(fields, 'patientId', String);

Expand Down
15 changes: 8 additions & 7 deletions imports/api/duration.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,25 +5,26 @@ const HOUR = 60 * MINUTE;
const DAY = 24 * HOUR;
const WEEK = 7 * DAY;

type UnitsRecord = Record<string, number>;
type UnitsArray = Array<[string, number]>;

export const units: UnitsRecord = {
export const units = {
week: WEEK,
day: DAY,
hour: HOUR,
minute: MINUTE,
second: SECOND,
millisecond: MILLISECOND,
};
} as const;

const DEFAULT_UNITS: UnitsArray = [
export type UnitsRecord = typeof units;

const DEFAULT_UNITS = [
['week', WEEK],
['day', DAY],
['hour', HOUR],
['minute', MINUTE],
['second', SECOND],
];
] as const;

export type UnitsArray = typeof DEFAULT_UNITS;

const DEFAULT_REST_UNIT = 'millisecond';

Expand Down
5 changes: 5 additions & 0 deletions imports/api/endpoint/EndpointError.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import {Meteor} from 'meteor/meteor';

const EndpointError = Meteor.Error;

export default EndpointError;
10 changes: 2 additions & 8 deletions imports/api/endpoint/Options.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,7 @@
import {type Meteor} from 'meteor/meteor';
import {type EJSONable, type EJSONableProperty} from 'meteor/ejson';
import type Serializable from '../Serializable';

type Options<
Result extends
| EJSONable
| EJSONable[]
| EJSONableProperty
| EJSONableProperty[],
> = {
type Options<Result extends Serializable> = {
wait?: boolean | undefined;
onResultReceived?:
| ((error: Error | Meteor.Error | undefined, result?: Result) => void)
Expand Down
9 changes: 5 additions & 4 deletions imports/api/endpoint/appointments/schedule.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,9 +27,10 @@ export default define({
} = sanitizeAppointmentUpdate(appointment);

assert($unset === undefined || Object.keys($unset).length === 0);
validate($set.begin, Date);
validate($set.end, Date);
validate($set.reason, String);
assert($set !== undefined);
assert($set.begin instanceof Date);
assert($set.end instanceof Date);
assert(typeof $set.reason === 'string');

const owner = this.userId;

Expand All @@ -38,7 +39,7 @@ export default define({
createPatient,
]);
} else {
validate($set.patientId, String);
assert(typeof $set.patientId === 'string');
const patient = await db.findOne(Patients, {
_id: $set.patientId,
owner,
Expand Down
12 changes: 7 additions & 5 deletions imports/api/endpoint/availability/next.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import define from '../define';
import properlyIntersectsWithRightOpenInterval from '../../interval/containsDate';
import isContainedInRightOpenIterval from '../../interval/beginsAfterDate';
import overlapsInterval from '../../interval/overlapsInterval';
import {Availability} from '../../collection/availability';
import {Availability, type SlotDocument} from '../../collection/availability';
import {
type Constraint,
type Duration,
Expand Down Expand Up @@ -36,7 +36,7 @@ export default define({

const owner = this.userId;

const properlyIntersecting = await db.fetch(
const properlyIntersecting: SlotDocument[] = await db.fetch(
Availability,
{
$and: [{owner}, properlyIntersectsWithRightOpenInterval(after)],
Expand All @@ -53,11 +53,13 @@ export default define({
return initialSlot(owner);
}

const slot = properlyIntersecting[0]!;

if (
properlyIntersecting[0].weight === 0 &&
overlapsAfterDate(after, duration, constraints, properlyIntersecting[0])
slot.weight === 0 &&
overlapsAfterDate(after, duration, constraints, slot)
) {
return properlyIntersecting[0];
return slot;
}

const firstContainedAndOverlapping = await db.findOne(
Expand Down
4 changes: 2 additions & 2 deletions imports/api/endpoint/compose.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@ import type Args from '../Args';
import type Context from './Context';
import type Endpoint from './Endpoint';

const compose = async <A extends Args, T>(
const compose = async <A extends Args, R>(
db: TransactionDriver,
endpoint: Endpoint<A, T>,
endpoint: Endpoint<A, R>,
invocation: Partial<Context>,
args: A,
) => {
Expand Down
1 change: 1 addition & 0 deletions imports/api/endpoint/documents/delete.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,5 +24,6 @@ export default define({

await db.updateOne(Documents, {_id: documentId}, {$set: {deleted: true}});
await updateLastVersionFlags(db, this.userId, document);
return undefined;
},
});
1 change: 1 addition & 0 deletions imports/api/endpoint/documents/restore.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,5 +24,6 @@ export default define({

await db.updateOne(Documents, {_id: documentId}, {$set: {deleted: false}});
await updateLastVersionFlags(db, this.userId, document);
return undefined;
},
});
1 change: 1 addition & 0 deletions imports/api/endpoint/documents/superdelete.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,5 +24,6 @@ export default define({

await db.deleteOne(Documents, {_id: documentId});
await updateLastVersionFlags(db, this.userId, document);
return undefined;
},
});
9 changes: 4 additions & 5 deletions imports/api/endpoint/invoke.ts
Original file line number Diff line number Diff line change
@@ -1,17 +1,16 @@
import {Meteor} from 'meteor/meteor';
import authorized from '../authorized';
import type Serializable from '../Serializable';

import type Args from '../Args';
import type Context from './Context';
import type Endpoint from './Endpoint';
import EndpointError from './EndpointError';

const EndpointError = Meteor.Error;

const invoke = async <A extends Args, R>(
const invoke = async <A extends Args, R extends Serializable>(
endpoint: Endpoint<A, R>,
invocation: Partial<Context>,
args: A,
): Promise<R | undefined> => {
): Promise<R> => {
if (!authorized(endpoint.authentication, invocation)) {
throw new EndpointError('not-authorized');
}
Expand Down
6 changes: 3 additions & 3 deletions imports/api/endpoint/patients/merge.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ export default define({
consultationIds: string[],
attachmentIds: string[],
documentIds: string[],
newPatient: Partial<PatientFields>,
newPatient: PatientFields,
) {
check(oldPatientIds, Array);
check(consultationIds, Array);
Expand All @@ -34,7 +34,7 @@ export default define({
consultationIds: string[],
attachmentIds: string[],
documentIds: string[],
newPatient: Partial<PatientFields>,
newPatient: PatientFields,
) {
// Here is what is done in this method
// (2) Check that each patient in `oldPatientIds` is owned by the user
Expand Down Expand Up @@ -165,7 +165,7 @@ export default define({
_consultationIds: string[],
_attachmentIds: string[],
_documentIds: string[],
_newPatient: Partial<PatientFields>,
_newPatient: PatientFields,
) {
return undefined;
},
Expand Down
4 changes: 2 additions & 2 deletions imports/api/makeObservedQueryHook.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import {type Meteor} from 'meteor/meteor';
import {type DependencyList, useEffect, useRef} from 'react';

import useForceUpdate from '../ui/hooks/useForceUpdate';
Expand All @@ -12,6 +11,7 @@ import type GenericQueryHook from './GenericQueryHook';
import findOneSync from './publication/findOneSync';
import type Selector from './Selector';
import type Options from './Options';
import type SubscriptionHandle from './publication/SubscriptionHandle';

const makeObservedQueryHook =
<R, T = R>(
Expand All @@ -22,7 +22,7 @@ const makeObservedQueryHook =
const loading = useRef<boolean>(true);
const results = useRef<any[]>([]);
const dirty = useRef<boolean>(false);
const handleRef = useRef<Meteor.SubscriptionHandle>(null);
const handleRef = useRef<SubscriptionHandle | null>(null);
const forceUpdate = useForceUpdate();

const effectWillTrigger = useChanged(deps);
Expand Down
8 changes: 4 additions & 4 deletions imports/api/patients.ts
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ const splitNames = (string: string) => {
const [firstname, ...middlenames] = names(string);
const firstnameWords = words(firstname ?? '');
const middlenameWords = words(middlenames.join(''));
return [firstnameWords, middlenameWords];
return [firstnameWords, middlenameWords] as const;
};

function normalizedName(firstname, lastname) {
Expand All @@ -71,7 +71,7 @@ const updateIndex = async (
deathdateModifiedAt,
sex,
}: PatientDocument,
$unset = undefined,
$unset?: {},
) => {
const [firstnameWords, middlenameWords] = splitNames(firstname);
const lastnameWords = keepUnique(words(lastname));
Expand Down Expand Up @@ -142,7 +142,7 @@ const sanitizePatientTag = ({
...rest,
});

const trimString = (value: string | undefined) => value?.trim();
const trimString = (value: any) => value?.trim();
const sanitizePatientTags = (tags) => list(map(sanitizePatientTag, tags));
const where = Match.Where;

Expand Down Expand Up @@ -307,7 +307,7 @@ function mergePatients(oldPatients: PatientFields[]): PatientFields {
for (const tag of tags) {
if (result.has(tag.name)) {
if (tag.comment) {
const newTag = result.get(tag.name);
const newTag = result.get(tag.name)!;
if (newTag.comment === undefined) {
newTag.comment = tag.comment;
} else {
Expand Down
5 changes: 5 additions & 0 deletions imports/api/publication/SubscriptionHandle.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import {type Meteor} from 'meteor/meteor';

type SubscriptionHandle = Meteor.SubscriptionHandle;

export default SubscriptionHandle;
28 changes: 16 additions & 12 deletions imports/api/publication/stats/frequencyBySex.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,25 +48,27 @@ export default define({
const inc = (patientId: string) => {
if (!pRefs.has(patientId))
throw new Error(`inc: patientId ${patientId} does not exist`);
const patient = pRefs.get(patientId);
count[patient.freq][patient.sex] -= 1;
const patient = pRefs.get(patientId)!;
count[patient.freq]![patient.sex] -= 1;
patient.freq += 1;
if (count[patient.freq] === undefined) count[patient.freq] = {};
if (count[patient.freq][patient.sex] === undefined)
count[patient.freq][patient.sex] = 0;
(count[patient.freq][patient.sex] as number) += 1;
if (count[patient.freq]![patient.sex] === undefined)
count[patient.freq]![patient.sex] = 0;
// eslint-disable-next-line @typescript-eslint/restrict-plus-operands
count[patient.freq]![patient.sex] += 1;
};

const dec = (patientId: string) => {
if (!pRefs.has(patientId))
throw new Error(`dec: patientId ${patientId} does not exist`);
const patient = pRefs.get(patientId);
count[patient.freq][patient.sex] -= 1;
const patient = pRefs.get(patientId)!;
count[patient.freq]![patient.sex] -= 1;
patient.freq -= 1;
if (count[patient.freq] === undefined) count[patient.freq] = {};
if (count[patient.freq][patient.sex] === undefined)
count[patient.freq][patient.sex] = 0;
(count[patient.freq][patient.sex] as number) += 1;
if (count[patient.freq]![patient.sex] === undefined)
count[patient.freq]![patient.sex] = 0;
// eslint-disable-next-line @typescript-eslint/restrict-plus-operands
count[patient.freq]![patient.sex] += 1;
};

let initializing = true;
Expand All @@ -83,14 +85,16 @@ export default define({
added(_id, {sex}) {
pRefs.set(_id, {freq: 0, sex});
if (count[0][sex] === undefined) count[0][sex] = 0;
(count[0][sex] as number) += 1;
// eslint-disable-next-line @typescript-eslint/restrict-plus-operands
count[0][sex] += 1;
commit();
},
changed(_id, {sex}) {
const {freq, sex: prev} = pRefs.get(_id);
count[freq][prev] -= 1;
if (count[freq][sex] === undefined) count[freq][sex] = 0;
(count[freq][sex] as number) += 1;
// eslint-disable-next-line @typescript-eslint/restrict-plus-operands
count[freq][sex] += 1;
pRefs.set(_id, {freq, sex});
commit();
},
Expand Down
2 changes: 1 addition & 1 deletion imports/api/publication/useItem.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import findOneSync from './findOneSync';
const useItem = <T, U = T>(
collection: Collection<T, U> | null,
selector: Selector<T>,
options: Options<T>,
options: Options<T> | undefined,
deps: DependencyList,
): U | undefined =>
useReactive(
Expand Down
Loading

0 comments on commit 3e6e80f

Please sign in to comment.