Skip to content

Fix: exclude null from params when they are not optional? #2669

@posva

Description

@posva

Currently creating a file pages/[version=semver].vue and the param parser semver as:


Bug: Exclude<ParamType, unknown[]> doesn't strip null from parsed param types

Summary

When a param parser's get returns T | T[] | null, the route map type uses Exclude<ParamType, unknown[]> to narrow array variants for non-repeatable params. This correctly removes T[] but leaves null, resulting in T | null instead of just T for required params.

Reproduction

  1. Define a param parser that returns a union including null:
import { defineParamParser } from 'vue-router/experimental'

interface MyType {
  value: string
}

export const parser = defineParamParser({
  get: (value): MyType | MyType[] | null => {
    if (!value) return null
    return Array.isArray(value) ? value.map((v) => ({ value: v })) : { value }
  },
  set: (value: MyType | null): string | null => (value ? value.value : null),
})
  1. Use this parser in a route (e.g. via definePage or route config) for a required path param like /pkg/:version.

  2. In the page component, access route.params.version - it is typed as MyType | null instead of MyType.

Expected

route.params.version should be MyType since it's a required path param. null should be excluded along with the array variant.

Actual

Type is MyType | null. Components need unnecessary null guards.

Root cause

Exclude<MyType | MyType[] | null, unknown[]> removes MyType[] (since it extends unknown[]) but keeps null (since null does not extend unknown[]).

Workaround

Avoid returning null from the parser's get function. Use miss() instead to signal missing/invalid values:

get: (value): MyType | MyType[] => {
  if (!value) return miss('Missing value')
  // ...
}

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    Status

    📆 Planned

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions