kitbagjs / router

A type safe router for vuejs
MIT License
131 stars 1 forks source link

Param defaults #195

Closed stackoverfloweth closed 3 weeks ago

stackoverfloweth commented 3 weeks ago

This PR introduces a feature we've wanted for as long as we've had params, default values.

From out initial release we've always had optional params. A param that is optional changes the route matching logic (regex), introduces the possibility of undefined for the type when accessing route.params.myParam, and correspondingly allows you to push to the route without supplying the optional param.

Defining an optional param on a route is driven by the question mark (?) inside the param syntax.

import { path } from '@kitbag/router'

{
  name: 'example-route',
  path: path('/path/[?sort]', { sort: String })
}

In this example, the sort will be type string | undefined.

After this PR, you'll be able to extend that functionality by defining a default value you wish to be used instead of undefined if no value is supplied/found. Let's extend the example above to provide a logic default value.

import { path, withDefault } from '@kitbag/router'

{
  name: 'example-route',
  path: path('/path/[?sort]', { sort: withDefault(String, 'asc' })
}

Now when we access the param, the type will be string.

import { useRoute } from '@kitbag/router'

const route = useRoute('example-route')

route.params.sort

Notice in my example I used the withDefault utility to take any Param and assign a default value. Developers also have the option of assigning a default when creating a custom param.

const myParam: ParamGetSet<'yes' | 'no'> = {
  get: (value, { invalid }) => {
    if (value !== 'yes' && value !== 'no') {
      invalid()
    }

    return value
  },
  set: value => value.toString(),
  defaultValue: 'no'
}
netlify[bot] commented 3 weeks ago

Deploy Preview for kitbag-router ready!

Name Link
Latest commit c7e28e8a2050e2ea9d52164f7ae63e2aba1a2a13
Latest deploy log https://app.netlify.com/sites/kitbag-router/deploys/666da1c136fadd000895c9b6
Deploy Preview https://deploy-preview-195--kitbag-router.netlify.app
Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.

To edit notification comments on pull requests, go to your Netlify site configuration.

pleek91 commented 3 weeks ago

Some thoughts based on this example of the syntax

path('/simple/[simple]', { 
  simple: withDefault(String, 'abc') 
})

Let's sync up on this. Love to see this coming together. Super cool feature, especially for things like a query param with a default value so that you don't have to deal with undefined everywhere in your component code.

stackoverfloweth commented 3 weeks ago

@pleek91 one more thing I'd like to add to this PR before merging is to see if we can fix the types so that a path like

{
  name: 'my-example',
  path: path('/path/[?id]', { id: withDefault(String, 'abc') }),
}

Accessing the param, params.id won't be string | undefined.

pleek91 commented 3 weeks ago

@pleek91 one more thing I'd like to add to this PR before merging is to see if we can fix the types so that a path like


{

  name: 'my-example',

  path: path('/path/[?id]', { id: withDefault(String, 'abc') }),

}

Accessing the param, params.id won't be string | undefined.

Agreed! That's an important piece.

stackoverfloweth commented 3 weeks ago

@pleek91 I fixed the types issue I was having yesterday. Params with default will remain optional when calling push, replace, etc but NOT be possibly undefined when reading router.route or useRoute.

I ended up going back on our decision to introduce a separate ParamGetSet and ParamGetSetWithDefault. That was helpful to discover where I was losing my default type but I was able to achieve the same end without changing as much.

image

I prefer having defaultValue?: T on ParamGetSet over defining another top level Param and having to include it in our big union of possible Param types. I think the devex of defining a param as :ParamGetSet<MyType> and not having to make the decision about defaults at that moment is better.