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

What are the types of MessageFunction's argument and option values? #27

Closed
stasm opened this issue Aug 18, 2023 · 2 comments
Closed

What are the types of MessageFunction's argument and option values? #27

stasm opened this issue Aug 18, 2023 · 2 comments

Comments

@stasm
Copy link
Contributor

stasm commented Aug 18, 2023

The signature of MessageFunction introduced in #22 is as follows:

type MessageFunction = (
  locales: string[],
  options: { [key: string]: unknown },
  input?: unknown
) => MessageValue;

In one of the earlier versions of the PR it was more specific:

type MessageFunction = (
  locales: string[],
  options: { [key: string]: MessageValue },
  input?: MessageValue
) => MessageValue;

Since we expect the users of the API to implement their own custom functions, it would be beneficial for their signatures to use narrower types with known methods, like formatToString().

However, even with narrower types, custom function implementations may need to do a lot of instanceof to handle different subclasses of MessageValue.

@eemeli
Copy link
Member

eemeli commented Dec 18, 2023

While the TS-ish types for these values is indeed unknown, this is what the proposal currently says about them:

The `input` and `options` values are constructed as follows:
- If the value is a literal defined in the message syntax,
the value is its `string` value.
- If the value is a variable referring to a local variable declaration,
the value is the `MessageValue` that the declaration's expression resolves to.
- Otherwise, the value is a variable referring to an external value,
and its type and value are that of the external value.

The idea here is for the function to make it sufficiently simple for a function to enforce its own expectations on its inputs to avoid the need to wrap every value in an otherwise unnecessary object wrapper. For instance :number does this:

Accepts as input any of the following:
- A number or a bigint.
This is used directly as the `value`.
- An object with a `valueOf()` method that returns a number or a bigint,
which is then used as the `value`.
- The JSON string representation of a number, to accommodate literal values as in `{42 :number}`.
The `value` is determined by the equivalent of calling `JSON.parse()` on the string,
and asserting that it returns a number or a bigint.

Its support for MessageValue-wrapped values that are coming from e.g. .input or .local declarations is handled by the second option, which also handles Number instance unwrapping.

For :string it's much simpler:

Accepts any input, and parses any non-string value using `String()`.
For no input, resolves its value to an empty string.

Could this approach be considered a suitable balance between performance and ease of use?

@eemeli
Copy link
Member

eemeli commented May 7, 2024

Closing as presumably answered.

@eemeli eemeli closed this as completed May 7, 2024
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

No branches or pull requests

2 participants