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

option: make Option.none and Option.some return Some<T> and None<T> #4326

Closed
wants to merge 2 commits into from

Conversation

coffeeispower
Copy link

@coffeeispower coffeeispower commented Jan 22, 2025

Type

  • Refactor
  • Feature
  • Bug Fix
  • Optimization
  • Documentation Update

Description

I was trying to use Option in a union where it is expected to be Some in some situations and None in others:

export interface AnonymousAuthenticationResult {
  readonly kind: 'anonymous';
  readonly user: None<User.User>;
  readonly session: None<Session.Session>;
  readonly workspace: None<Workspace.Workspace>;
}
export interface UserAuthenticationResult {
  readonly kind: 'user';
  readonly user: Some<User.User>;
  readonly session: Some<Session.Session>;
  readonly workspace: Option.Option<Workspace.Workspace>;
}
export interface WorkspaceAuthenticationResult {
  readonly kind: 'workspace';
  readonly user: None<User.User>;
  readonly session: None<Session.Session>;
  readonly workspace: Some<Workspace.Workspace>;
}
export type AuthenticationResult =
  | UserAuthenticationResult
  | WorkspaceAuthenticationResult
  | AnonymousAuthenticationResult;

However, since Option.some and Option.none return Option<T>, it becomes non-ergonomic to create these structures, since you have to cast manually to Some or None

const authResult: AuthenticationResult = {
  kind: "workspace",
  user: Option.none() as None<User.User>,
  session: Option.none() as None<Session.Session>,
  workspace: Option.some(workspace) as Some<Workspace.Workspace>
};

which doesn't make any sense because it is expected that Option.some always returns Some, and Option.none always returns None

Copy link

changeset-bot bot commented Jan 22, 2025

⚠️ No Changeset found

Latest commit: 2c9bf69

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. If these changes should result in a version bump, you need to add a changeset.

This PR includes no changesets

When changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types

Click here to learn what changesets are, and how to add one.

Click here if you're a maintainer who wants to add a changeset to this PR

@tim-smart
Copy link
Contributor

I would recommend making your state more explicit

export interface AnonymousAuthenticationResult {
  readonly kind: "anonymous"
}

export interface UserAuthenticationResult {
  readonly kind: "user"
  readonly user: User.User
  readonly session: Session.Session
  readonly workspace: Option.Option<Workspace.Workspace>
}

export interface WorkspaceAuthenticationResult {
  readonly kind: "workspace"
  readonly workspace: Workspace.Workspace
}

export type AuthenticationResult =
  | UserAuthenticationResult
  | WorkspaceAuthenticationResult
  | AnonymousAuthenticationResult

@coffeeispower
Copy link
Author

coffeeispower commented Jan 24, 2025

@tlm-smart but then in the api routes I have to check the kind. The reason i made all of the properties exist in all variants is because then I don't have to check the kind to access them. Like for example the workspace field, the api route should not care if it's kind == "workspace" or kind == "user", it should work the same way.
The authentication result is basically the result of a authentication middleware, it's the object that's injected into the request context after the middleware is executed.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
Archived in project
Development

Successfully merging this pull request may close these issues.

2 participants