Skip to content

Intl.NumberFormat: missing options, and discussion on typing conventions #56269

Closed
@Renegade334

Description

@Renegade334

⚙ Compilation target

ESNext

⚙ Library

intl

Missing / Incorrect Definition

This was originally just going to highlight some missing NumberFormat definitions, but after a trawl through the library, rather grew in scope a bit.

I've therefore divided this issue down into three parts: two are details of changes that need to be made to the library, but the third is an RFD that arose out of inconsistencies in the Intl library definitions. If the project team feel this would be better forked elsewhere, then feel free.

1: Properties of NumberFormatOptions/ResolvedNumberFormatOptions diverging from previous specifications

es5.d.ts – ECMA-402 1.0 (2012)
  • currencySign is defined as a property here, but does not exist in the specification
  • currencyDisplay is not defined as a property here, but exists in the specification as "code" | "symbol" | "name" | undefined
es2020.intl.d.ts – ECMA-402 7.0 (2020)
  • currencyDisplay should be removed (as should have been defined above)
  • numberingSystem is not defined as a property of NumberFormatOptions here, but exists in the specification as string | undefined

2: NumberFormatOptions changes in ECMA-402 10.0 (2023)

es2023.intl.d.ts should ideally be created to house these changes.

  • breaking changes from es2020.intl.d.ts:
    - useGrouping?: boolean | undefined;
    + useGrouping?: "min2" | "auto" | "always" | boolean | undefined;
    - signDisplay?: "auto" | "never" | "always" | "exceptZero" | undefined;
    + signDisplay?: "auto" | "never" | "always" | "exceptZero" | "negative" | undefined;
  • the following new properties have been added in the specification:
    roundingPriority?: "auto" | "morePrecision" | "lessPrecision" | undefined;
    roundingIncrement?: 1 | 2 | 5 | 10 | 20 | 25 | 50 | 100 | 200 | 250 | 500 | 1000 | 2000 | 2500 | 5000 | undefined;
    roundingMode?: "ceil" | "floor" | "expand" | "trunc" | "halfCeil" | "halfFloor" | "halfExpand" | "halfTrunc" | "halfEven" | undefined;
    trailingZeroDisplay?: "auto" | "stripIfInteger" | undefined;
  • corresponding changes to ResolvedNumberFormatOptions:
    - useGrouping: boolean;
    + useGrouping: "min2" | "auto" | "always";
    - signDisplay?: "auto" | "never" | "always" | "exceptZero";
    + signDisplay?: "auto" | "never" | "always" | "exceptZero" | "negative";
    roundingMode: "ceil" | "floor" | "expand" | "trunc" | "halfCeil" | "halfFloor" | "halfExpand" | "halfTrunc" | "halfEven";
    roundingIncrement: 1 | 2 | 5 | 10 | 20 | 25 | 50 | 100 | 200 | 250 | 500 | 1000 | 2000 | 2500 | 5000;
    trailingZeroDisplay: "auto" | "stripIfInteger";

 

3: Discussion – primitives versus const unions for enum-like properties

There are a lot of properties in the Intl specification that accept an enum-like list of values as valid input.

There is no set standard in the library for how these are defined.

  • es5.d.ts tended to keep types as wide as possible, such as style?: string | undefined
  • subsequent library updates tended to narrow enum-like types to const unions, such as compactDisplay?: "short" | "long" | undefined

The latter has obvious advantages in terms of developer usability. However, it has a significant drawback, in that these enum-like properties have had a tendency to be modified fairly frequently in recent versions of the specification.

When this occurs to properties defined using primitive types, this isn't an issue for developers, as the change is non-breaking.
For example, the style property was defined in the original specification as "decimal" | "percent" | "currency" | undefined, but was added to the library as string | undefined; as such, when "unit" was added as a style in ES2020, the change went unnoticed.

However, when this occurs to properties defined as const unions, such as with a couple of the examples above, it's a different story.

  • Firstly, the new property values can't be used until they're added into the library, despite the primitive type of the property not having changed.
  • Secondly, making the changes to the library is going to have to involve some sort of workaround, as modifying the type of an existing interface property is obviously not possible.

As such, I think the project needs to decide on a couple of conventions:

  1. Should enum-like properties in the Intl library be typed as "const" | "unions" | "where" | "possible", or should they be widened to their equivalent primitive?
  2. If the former is chosen, then whenever an enum-like property is modified in the specification, this will necessitate modifying existing interface properties in the Intl library; what is the best way of implementing these changes?

Sample Code

No response

Documentation Link

No response

Metadata

Metadata

Assignees

No one assigned

    Labels

    Domain: lib.d.tsThe issue relates to the different libraries shipped with TypeScriptHelp WantedYou can do thisSuggestionAn idea for TypeScript

    Type

    No type

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions