Skip to content

v8.0.0

Compare
Choose a tag to compare
@cat394 cat394 released this 15 Oct 04:35
· 40 commits to main since this release

Enhanced Union String in the Constraint Area

The highlight of this milestone release, version 8, is the enhanced union strings in the constraint area!

Previously, we could apply two types of constraints to parameter types:

  1. Single Type Constraint

    "/users/:id<string>" // => { id: string }
  2. Union Type Constraint with Literal Types

    "/users/:id<(a|1|true)>" // => { id: "a" | 1 | true }

However, there were some type patterns that couldn't be achieved with this approach.

For example, you couldn’t create a union of primitive types like string|number. There may also be situations where you want to handle values like "123" or "true" as strings without automatic type conversion.

Unfortunately, this was not possible in v7. If you specified <(string|number)>, it would generate a union of string literals like "string"|"number".

To address this, in v8 we introduced manual type conversion support, allowing conversions to primitive types.

This transition is intuitive, simple, and extremely easy to implement!

The key thing to remember is to add * before the elements in the union string that need to be converted!

This means that any union string without the * prefix will be treated as a union of string literals.

Prior to v7

const route_config = {
  route_1: {
    path: "/:param<(string|number)>"
  },
 route_2: {
   path: "/:param<(a|10|true)>"
 }
} as const satisfies RouteConfig;

// ...create link generator

link("route_1", { param: "number" });
// Param type is { param: "string" | "number" }

link("route_2", { param: 10 });
// Param type is { param: "a" | 10 | true }

From v8 onwards

const route_config = {
  route_1: {
    path: "/:param<(string|number)>" // No automatic type conversions
  },
  route_2: {
    path: "/:param<(*string|*number)>"
  },
  route_3: {
    path: "/:param<(abc|123|boolean)>" // No automatic type conversions
  },
  route_4: {
    path: "/:param<(abc|*123|*boolean)>"
  }
} as const satisfies RouteConfig;

// ...create link generator

link("route_1", { param: "number" });
// Param type is { param: "string" | "number" }

link("route_2", { param: 123 });
// Param type is { param: string | number }

link("route_3", { param: "boolean" });
// Param type is { param: "abc" | "123" | "boolean" }

link("route_4", { param: true });
// Param type is { param: "abc" | 123 | boolean }

The only breaking change from v7 is this! Since it only affects type inference and does not change function implementations, you can migrate with confidence.

Other Improvements

  • Resolved ambiguities in type inference.
  • Clarified internal function names and variable names.
  • Updated and revised the documentation for v8.