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

Remove const modifier from result type #91

Closed
wants to merge 1 commit into from

Conversation

masad-frost
Copy link
Member

@masad-frost masad-frost commented Apr 30, 2024

Adding const generic modifier to our result functions makes it so that it's not possible to pass in arrays (possibly other things that are affected) to Ok (or Err).

For example

import {
  ServiceSchema,
  RiverUncaughtSchema,
  Procedure,
  Ok,
} from '@replit/river';
import { Type } from '@sinclair/typebox';

const SomethingWithArray = Type.Object({
  arr: Type.Array(Type.String()),
});

export const Service = ServiceSchema.define(
  {
    initializeState: () => ({}),
  },
  {
    initialize: Procedure.subscription({
      input: Type.Object({}),
      output: SomethingWithArray,
      errors: RiverUncaughtSchema,
      async handler(ctx, input, outputStream) {
        outputStream.push(
          Ok({
            arr: ['a', 'b'],
//         ^ ERROR, arr is not readonly
          }),
        );
      },
    }),
  },
);

I honestly don't understand what's going on here, and why we added the const modifier in the first place, so let me know if we should find another way to fix this.

Maybe we meant to do this instead? Produce a read-only result.

export function Ok<T, E>(payload: T): Result<const T, const E> {
  return {
    ok: true,
    payload,
  };
}

@Monkatraz
Copy link
Contributor

Here is why we added it, quoting for posterity:

If you have a strictly typed result like this:

const MyOutput = Type.Object({ str: Type.Literal('foo') })
type MyResult = Result<Static<typeof MyOutput>, never>

then, counter-intuitively, this may not compile (without const generics):

const myResult: MyResult = Ok({ str: 'foo' })

this is because the object inside the Ok is typed broadly, like { str: string }. It will compile if you do this though:

const myResult: MyResult = Ok({ str: 'foo' } as const)

which is annoying to have to type every time. The solution is to use const generics, which just does the as const for you (literally, that's all it does).

@masad-frost
Copy link
Member Author

Closing because this is a typescript bug fixed in version 5.3

@masad-frost masad-frost deleted the fm-no-const-modifier branch April 30, 2024 21:29
@masad-frost
Copy link
Member Author

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.

None yet

2 participants