Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Make Context.state type to {} by default #1284

Merged
merged 1 commit into from
Aug 22, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 35 additions & 2 deletions docs/blog/version-5.0-release-notes.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,40 @@ Version 5.0 of [Foal](https://foalts.org/) is out!

- Support for Node 18 has been dropped and support for Node 22 has been added.

## Removal of depreacted components
## Better typing

- The deprecated hook `@Log` has been removed. To replace it, you can use the `Logger` service in a custom `@Hook`.
- The default type of `Context.state` is now `{}`. This way, you'll get a compilation error if you forget to specify a type for the state.

```typescript
// Version 4
class MyController {
@Get('/foobar')
foobar(ctx: Context) {
// Does not throw.
console.log(ctx.state.shoppingCart);
}
}

// Version 5
class MyController {
@Get('/foobar')
foobar(ctx: Context) {
// Throws a compilation error: Property 'shoppingCart' does not exist on type '{}'.ts(2339)
console.log(ctx.state.shoppingCart);
}
}

// Version 5 (without error)
class MyController {
@Get('/foobar')
foobar(ctx: Context<any, { shoppingCart: object }>) {
console.log(ctx.state.shoppingCart);
}
}

```

## Removal of deprecated components

- The deprecated hook `@Log` has been removed. Use the `Logger` service in a custom `@Hook` instead.
- The command alias `npx foal run-script` has been removed. Use `npx foal run` instead.
2 changes: 1 addition & 1 deletion docs/docs/architecture/controllers.md
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ It has seven properties:
| Name | Type | Description |
| --- | --- | --- |
| `request` | `Request` | Gives information about the HTTP request. |
| `state` | `{ [key: string]: any }` | Object which can be used to forward data accross several hooks (see [Hooks](./hooks.md)). |
| `state` | `{ [key: string]: any } = {}` | Object which can be used to forward data accross several hooks (see [Hooks](./hooks.md)). |
| `user` | `{ [key: string]: any }`\|`null` | The current user (see [Authentication](../authentication/quick-start.md)). |
| `session`| `Session`\|`null` | The session object if you use sessions. |
| `files` | `FileList` | A list of file paths or buffers if you uploaded files (see [Upload and download files](../common/file-storage/upload-and-download-files.md)). |
Expand Down
4 changes: 2 additions & 2 deletions docs/docs/architecture/hooks.md
Original file line number Diff line number Diff line change
Expand Up @@ -465,7 +465,7 @@ import { Context, Get, Hook, HttpResponseOK, UserRequired } from '@foal/core';
import { Org } from '../entities';

function AddOrgToContext() {
return Hook(async ctx => {
return Hook(async (ctx: Context<any, { org: Org }>) => {
if (ctx.user) {
ctx.state.org = await Org.findOneByOrFail({ id: ctx.user.orgId });
}
Expand All @@ -477,7 +477,7 @@ export class ApiController {
@Get('/org-name')
@UserRequired()
@AddOrgToContext()
readOrgName(ctx: Context) {
readOrgName(ctx: Context<any, { org: Org }>) {
return new HttpResponseOK(ctx.state.org.name);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ describe('Feature: Forwarding data betweens hooks', () => {
/* ======================= DOCUMENTATION BEGIN ======================= */

function AddOrgToContext() {
return Hook(async ctx => {
return Hook(async (ctx: Context<any, { org: Org }>) => {
if (ctx.user) {
ctx.state.org = await Org.findOneByOrFail({ id: ctx.user.orgId });
}
Expand All @@ -33,7 +33,7 @@ describe('Feature: Forwarding data betweens hooks', () => {
@Get('/org-name')
@UserRequired()
@AddOrgToContext()
readOrgName(ctx: Context) {
readOrgName(ctx: Context<any, { org: Org }>) {
return new HttpResponseOK(ctx.state.org.name);
}

Expand Down
2 changes: 1 addition & 1 deletion packages/core/src/core/http/context.ts
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,7 @@ interface Request extends IncomingMessage {
* @class Context
* @template User
*/
export class Context<User = { [key: string]: any } | null, ContextState = { [key: string]: any }> {
export class Context<User = { [key: string]: any } | null, ContextState extends { [key: string]: any } = {}> {
readonly request: Request;
session: Session | null;

Expand Down
2 changes: 1 addition & 1 deletion packages/socket.io/src/architecture/websocket-context.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ import { Session } from '@foal/core';
* @template ContextSession
* @template ContextState
*/
export class WebsocketContext<User = { [key: string]: any } | null, ContextState = { [key: string]: any }> {
export class WebsocketContext<User = { [key: string]: any } | null, ContextState extends { [key: string]: any } = {}> {
readonly socket: Socket;
session: Session | null;

Expand Down
Loading