31 instances of as Record<string, string> on TanStack Router params props. The cause is not a typing problem in the router or the branded IDs. Every one of them sits next to a to={'...' as string} cast, and there are exactly 31 of each.
// packages/web/src/components/admin/UserTable.tsx:57-58
<Link
to={'/admin/users/$userId' as string}
params={{ userId: user.id } as Record<string, string>}
Casting to to string erases the route type, so the router can no longer infer the params shape, so the params object no longer typechecks, so it gets cast too. The second cast is a consequence of the first.
Verified
routeTree.gen.ts contains every admin route the casts point at. Removing both casts from the two sites in UserTable.tsx (to='/admin/users/$userId', params={{ userId: user.id }}) and running tsc --noEmit in packages/web produces no errors. Branded IDs are not involved: UserId is assignable to string, and the uncast form accepts user.id as-is.
The pattern first appears in d298306f and was copied forward through #747 and #767. The most likely origin is authoring a route file and the links to it in the same change, before the route tree regenerated, then copying the shape.
Done when
- No
to={'...' as string} / to: '...' as string in packages/web/src (31 today)
- No
as Record<string, string> on params or search props (31 today; the 7 remaining as Record<string, string> in the repo are unrelated: Stripe metadata, RESPONSE_LABELS lookups, export-pdf.ts)
- A grep in CI or lint for
' as string} on to= so it stops growing
Effort: ~1 hour, mechanical. Nothing to investigate.
Part of #778 (TypeScript correctness target state and tracker).
31 instances of
as Record<string, string>on TanStack Routerparamsprops. The cause is not a typing problem in the router or the branded IDs. Every one of them sits next to ato={'...' as string}cast, and there are exactly 31 of each.Casting
totostringerases the route type, so the router can no longer infer the params shape, so the params object no longer typechecks, so it gets cast too. The second cast is a consequence of the first.Verified
routeTree.gen.tscontains every admin route the casts point at. Removing both casts from the two sites inUserTable.tsx(to='/admin/users/$userId',params={{ userId: user.id }}) and runningtsc --noEmitinpackages/webproduces no errors. Branded IDs are not involved:UserIdis assignable tostring, and the uncast form acceptsuser.idas-is.The pattern first appears in
d298306fand was copied forward through #747 and #767. The most likely origin is authoring a route file and the links to it in the same change, before the route tree regenerated, then copying the shape.Done when
to={'...' as string}/to: '...' as stringinpackages/web/src(31 today)as Record<string, string>onparamsorsearchprops (31 today; the 7 remainingas Record<string, string>in the repo are unrelated: Stripe metadata,RESPONSE_LABELSlookups,export-pdf.ts)' as string}onto=so it stops growingEffort: ~1 hour, mechanical. Nothing to investigate.
Part of #778 (TypeScript correctness target state and tracker).