Skip to content

SSF-131/138 Strict Mode#105

Open
Juwang110 wants to merge 18 commits intomainfrom
jw/SSF-131-strict-mode
Open

SSF-131/138 Strict Mode#105
Juwang110 wants to merge 18 commits intomainfrom
jw/SSF-131-strict-mode

Conversation

@Juwang110
Copy link

ℹ️ Issue

Closes https://vidushimisra.atlassian.net/jira/software/projects/SSF/boards/1?selectedIssue=SSF-131 and
https://vidushimisra.atlassian.net/jira/software/projects/SSF/boards/1?selectedIssue=SSF-138

📝 Description

This PR enables typescript strict mode in the backend which enables the compiler to be a lot more picky and strict with types, null and undefined checks, etc. The PR includes changes to make our backend adhere with all the rules that strict mode enforces. This involved work making entity fields optional or required, and also handling null/undefined errors and return values.

✔️ Verification

I made sure all the backend tests pass and npx nx serve backend properly runs without error.

🏕️ (Optional) Future Work / Notes

N/A

@dburkhart07 dburkhart07 self-requested a review February 15, 2026 21:15
@sam-schu sam-schu self-requested a review February 15, 2026 21:56
Copy link

@dburkhart07 dburkhart07 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Some initial changes

foodType: FoodType;
name!: string;
quantity!: number;
foodType?: FoodType;

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should this not be required?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Based on the DB, a donation items foodType can be null. I'm not sure if that makes sense though...

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, food type should not be nullable in the db...

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

will make migration

Copy link
Collaborator

@sam-schu sam-schu left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

First half of review

@Column({ name: 'fulfilled_at', type: 'timestamp' })
fulfilledAt: Date;
@Column({ name: 'fulfilled_at', type: 'timestamp', nullable: true })
fulfilledAt?: Date | null;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can these fields actually be undefined or null, or does it always come back one way or the other if the database column is null?


return response.UserConfirmed;
} catch (err: unknown) {
throw new BadRequestException('Failed to sign up user');
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Bad request implies that it's the client's fault, if we don't really know what caused the error then I'd suggest going with an internal server error

await this.providerClient.send(adminDeleteUserCommand);
}

validateAuthenticationResultTokensForSignIn(
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should these methods be private?


const response = await this.providerClient.send(signInCommand);

this.validateAuthenticationResultTokensForSignIn(response);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For both of these functions, can we return the authentication result from the function with a type that will avoid having to do non-null assertions?

import { Request } from 'express';
import { User } from '../users/user.entity';

export interface AuthenticatedRequest extends Request {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I got confused by this at first - could you add a comment explaining that user does not have to be provided by the client but is instead added automatically by the auth backend?

): Promise<FoodRequest> {
if (
!Object.values(RequestSize).includes(body.requestedSize as RequestSize)
!Object.values(RequestSize).includes(
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we still need this check now that we have the DTO?

requestedSize!: RequestSize;

@ArrayNotEmpty()
requestedItems!: string[];
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shouldn't this be limited to the valid food types?

@IsOptional()
@IsString()
@IsNotEmpty()
@MaxLength(255)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We shouldn't need a max length here since the corresponding database column is of type text (some of ours are varchar(255) and need this for that reason)

const createBody = {
pantryId: 1,
requestedSize: RequestSize.MEDIUM,
requestedItems: ['Test item 1', 'Test item 2'],
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we change these to valid food types?

describe('POST /create', () => {
it('should call requestsService.create and return the created food request', async () => {
const createBody: Partial<FoodRequest> = {
const createBody = {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is the cast necessary here or can we just type this object normally?

status: order.status,
foodManufacturerName: order.foodManufacturer.foodManufacturerName,
foodManufacturerName:
order.foodManufacturer?.foodManufacturerName ?? undefined,
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think this is necessary

name: allocation.item.itemName,
quantity: allocation.allocatedQuantity,
foodType: allocation.item.foodType,
foodType: allocation.item.foodType ?? undefined,
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Noting here for after the migration that we won't need this either

@IsNotEmpty({ each: true })
@MaxLength(255, { each: true })
restrictions?: string[];
restrictions!: string[];
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What was the reason for this change?

await expect(controller.getCurrentUserPantryId({})).rejects.toThrow(
new UnauthorizedException('Not authenticated'),
);
await expect(
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This case seems important enough that it is an expected case for the function to need to deal with, which is making me think that maybe we should be typing the controller function to take in a Request | AuthenticatedRequest instead of assuming it will always be an AuthenticatedRequest?

"compilerOptions": {
"esModuleInterop": true
"esModuleInterop": true,
"strict": true
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

very epic and awesome line of code right here that I am very excited for !!

export interface CreateRequestDto {
pantryId: number;
requestedSize: RequestSize;
requestedItems: string[];
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same comment here as in the backend

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't see any package.json changes?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants

Comments