33 KiB
any Usage Audit — what each one should be
Branch: DEAD_CODE_CLEAN
Scope: all any keyword usages in apps/* and packages/* source (.ts/.tsx), excluding node_modules, dist, .wrangler, .output, .expo, .turbo, .tanstack, dumps, *.sql, and generated route trees (routeTree.gen.ts).
Nature: documentation only — no code changed.
Totals (type-level any, excluding prose/comments/generated)
| Area | Count | Dominant cause |
|---|---|---|
apps/backend |
~85 | as any casts on JWT/Drizzle/error shapes; : any where a shared type exists |
packages/db_helper_sqlite + _postgres |
~105 | (x: any) on already-typed Drizzle results; Promise<any> helpers |
apps/admin-ui |
~161 | onError/catch (e: any); router.push(... as any); entity useState<any> |
apps/user-ui + apps/fallback-ui |
~137 | catch/onError; Expo/TanStack as any; catalog/cart item: any |
apps/web-ui |
~138 | Record<number, any>/(p: any) product+slot callbacks; onError |
apps/admin-web |
~128 | onError/catch (36); domain rows; navigate({ to: ... as any }) |
packages/shared + web-components + ui + migrator |
~28 | untyped component props; RN style/asset props; migrator rows |
| Total | ~780 |
Regex-based raw totals are a bit higher because the word "any" also appears in comments/prose and tsconfig files; those are excluded here.
The replacement playbook ("what it should have been")
catch (e: any)/onError: (e: any)→unknown(and narrow withe instanceof Error ? e.message : '…'). This is the single largest mechanical category (~100 sites across the repo).onError: (error: any)on tRPC hooks → delete the annotation. tRPC v11 already infersTRPCClientError<AppRouter>;.messagekeeps working.- Callback params on typed Drizzle/array results → delete
: any. Becausedb_index.tspasses the fullschematodrizzle(...),db.query.*and.select()results are fully inferred;(x: any) => …is pure noise. (item: any)/(product: any)in catalog/cart lists → the real entity type:MergedProduct(catalog),CartItem(carts),AdminSku,AdminSlotWithProducts,AdminOrderDetails,UserOrderSummary, etc.router.push(… as any)→ typed routes (Hreffromexpo-router;FileRouteTypes['to']/generated union for TanStack Router). Static routes can simply drop the cast.Record<string, any>→Record<string, unknown>for heterogeneous bags.z.any()→z.unknown()in Zod schemas (or a precise union).- RN/Expo props → their real types:
StyleProp<ViewStyle>/StyleProp<ImageStyle>,NativeSyntheticEvent<NativeScrollEvent>,TextStyle['fontWeight'],ImagePicker.ImagePickerAsset. - Icon
name={x as any}→React.ComponentProps<typeof MaterialIcons>['name'](the glyph-key union). Promise<any>db-helper returns →InferSelectModel<typeof table>/ explicitPick<Row, …>.
Highest-leverage shared fixes (fix once, removes many)
These untyped shared declarations force any at dozens of call sites — tighten them first:
| Fix | File | Impact |
|---|---|---|
value: any → a ConstValueType | ConstValueType[] union (union already defined at line 18) |
packages/shared/types/const.types.ts:8 |
Removes value.map((id: any) => …) in admin-ui and admin-web reorder screens |
ListItemProps.item: any, CompactProductCardProps.item: any, OffersSectionProps.products: any[], AddedToCartProduct.product: any → hoist a shared structural product type (or make the props generic) |
packages/shared/types/app-common.types.ts:60,78,87,96 |
Caps how far web-ui/user-ui flash/offers/complaints props can be tightened |
queryParams?: Record<string, any> → Record<string, unknown> |
packages/shared/types/app-common.types.ts:20 |
Consumer only does String(value) |
setFile: (file: any) => void → ImagePickerAsset | ImagePickerAsset[] | null |
packages/ui/src/components/use-pick-image.tsx:13 |
Type flows into admin-ui setFile: (assets: any) (3 sites) and profile-image/ImageUploaderNeo |
Export app-local entity types: MergedProduct, CartItem, SlotInfo/ProductSlotMap (web-ui/user-ui); ProductFormData, Variant, Attribute, CouponFormValues (admin-ui/admin-web) |
respective hook/component files | Removes dozens of values: any / item: any in mutations and list callbacks |
Backend procedures returning any[] (coupon getAll/getReservedCoupons, admin getUserIncidents, store) → concrete shared types |
apps/backend/.../admin-apis/apis/{coupon,user,store}.ts |
Removes the downstream Coupon/UserIncident anys in both admin frontends |
apps/backend
Summary
- 85
anykeywords across 83 lines / 31 files. - Top files:
coupon.ts&const-store.ts(7 each),admin/user.ts,post-order-handler.ts,app.ts(6 each),admin/product.ts(5),auth.ts,cache-creator.ts(4). - Dominant patterns: (1)
x as anyaround JWT payloads, Drizzlejsoncolumns, and untyped db-helper returns; (2): anyparams/locals where a concrete shared type exists (OrderWithFullData,AdminVendorSnippet,TagBasicData,StaffRole); (3) generic defaults<T = any>and catch clauses. - 10 of the 85 are inside commented-out "Old implementation" blocks → delete, don't retype.
| Location | Current code | Should be | Why |
|---|---|---|---|
app.ts:57, middleware/auth.middleware.ts:19 |
const decoded = payload as any |
AppJwtPayload = { userId?: number; staffId?: number; name?: string } |
jose JWTPayload; tokens are signed as SignJWT({ userId }) / SignJWT({ staffId, name }) |
app.ts:131,132 |
(err as any).statusCode |
err instanceof ApiError ? err.statusCode |
ApiError is the only error with statusCode |
app.ts:134,135 |
(err as any).status |
err instanceof HTTPException ? err.status |
Hono HTTPException |
app.ts:141 |
c.json({ message }, status as any) |
status as StatusCode |
Hono status union |
types/hono.d.ts:5, trpc/trpc-index.ts:7 |
user?: any |
AppJwtPayload |
consumed as ctx.user?.userId |
trpc/trpc-index.ts:37 |
const err = error as any |
unknown + narrow |
catch var; reads name/message/code/stack/meta/sql |
jobs/cache-creator.ts:10,13 |
state: any |
DurableObjectState |
uses storage/alarm |
jobs/cache-creator.ts:11,13 |
env: any |
WorkerEnv (needs domain input) |
passed to ensureWorkerInit |
jobs/payment-status-checker.ts:3,4,5 |
payment:any; order:any; slot:any |
typeof payments.$inferSelect / {id;userId} / row types |
stub interface; only order.id/.userId read |
lib/queue-consumer.ts:4,27,40 |
batch: any |
MessageBatch<NotifQueueMessage> / <{orderIds:number[]}> / <CancellationMessage> |
pushed message shapes are known |
lib/const-store.ts:34,58 |
<T = any> |
<T = unknown> |
generic default |
lib/const-store.ts:90,102,107 |
Record<…, any> |
Record<…, unknown> |
opaque KV values |
lib/api-error.ts:3,5 |
details?: any |
unknown |
never consumed typed |
lib/notif-job.ts:11,22 |
notificationQueue:any, notificationWorker:any |
bullmq Queue/Worker or Record<string, never> |
stubbed ({}) |
lib/notif-job.ts:91 |
scheduleNotification(userId, payload: any, …) |
{ title; body; type; orderId? } |
callers pass exactly this |
lib/worker-init.ts:3,4 |
env: any, (globalThis as any).ENV |
WorkerEnv / typed global |
matches existing typed-global pattern |
lib/post-order-handler.ts:44,52,95,167,168 |
ordersData: any[], (item: any), createdOrders: any[], Map<…, any[]> |
OrderWithFullData[], OrderWithFullData['orderItems'][number], PlacedOrder[] |
db-helper return types |
lib/post-order-handler.ts:86 |
orderData: any |
OrderWithCancellationData & { refundStatus: string } |
known shape |
lib/flash-delivery-cron.ts:12 |
env: any |
WorkerEnv |
|
lib/env-exporter.ts:62 |
(globalThis as any).ENV || (globalThis as any).process?.env |
typed structural cast | matches rest of codebase |
lib/notif-job.ts:91, trpc/.../staff-user.ts:64,112 |
mixture | AdminVendorSnippet, StaffRole |
concrete shared types exist |
admin-apis/apis/store.ts:17,37 |
stores: any[], store: any |
Store & { owner: User } |
query includes owner |
admin-apis/apis/banner.ts:59, user-apis/apis/auth.ts:274 |
catch (e: any) |
unknown + narrow |
|
admin-apis/apis/const.ts:38 |
z.any() |
z.unknown() |
|
admin-apis/apis/slots.ts:74 |
deliverySequence: z.any() |
Record<string, number[]> union |
shared AdminDeliverySequence |
user-apis/apis/payments.ts:129 |
payload as any |
Record<string, unknown> |
schema is jsonText<unknown> |
admin-apis/apis/product.ts:265,357,754 |
as any casts / product: any |
CreateProductInput / AdminProductTagWithProducts |
helpers/return types exist |
user-apis/apis/user.ts:61, auth.ts:110,374 |
new Date(userDetail.dateOfBirth as any) |
drop cast | field is Date | null |
user-apis/apis/order.ts:293 |
slotId: null as any |
null |
param is number | null |
admin-apis/apis/coupon.ts:129,141,153,154,351,366,440 |
coupons: any[], Promise<any>, (au:any), (ap:any), coupon: any |
Coupon & { applicableUsers; applicableProducts } / ReservedCoupon (needs domain input) |
relations not modelled in shared |
common-apis/common.ts:79,84,85 |
(id:any), (tag:any), orderedTags:any[] |
number, TagBasicData, TagBasicData[] |
getConstant<T> default; getAllTagsForCache() |
admin-apis/apis/user.ts:48,60,98,117,170,258 |
(u:any) etc |
Pick<User,…>, Pick<PlacedOrder,…>, UserIncident (needs domain input) |
select shapes |
Dead-code anys (delete) |
product.ts:565,700, banner.ts:194, slots.ts:176,347, address.ts:192, admin/order.ts:384, vendor-snippets.ts:260, const-store.ts:91,97 |
— | commented-out old impls |
Easy wins: drop redundant as any (product.ts:265/357, order.ts:293, user.ts:61, auth.ts:110/374, payments.ts:129); : any→unknown (api-error, const-store generics, payment-status-checker, payments-utils); catch→unknown (banner.ts:59, auth.ts:274); z.any()→z.unknown(); delete dead anys; define AppJwtPayload once.
packages/db_helper_sqlite + db_helper_postgres
Summary: 105 tokens across 98 lines / 17 files. Top: sqlite/admin-apis/product.ts (27), sqlite/admin-apis/order.ts (19), run-batched.ts (7), admin-apis/user.ts (7 each pkg), admin-apis/coupon.ts (6 each). Dominant: (x: any) on already-typed Drizzle results (~60) — just delete. Row<T> = InferSelectModel<typeof T>, Insert<T> = InferInsertModel<typeof T>.
| Location | Current code | Should be | Why |
|---|---|---|---|
sqlite/admin-apis/product.ts:182,235,385,483,530 |
(ci|f: any) |
CreateComboItemInput / SkuFeatureLike |
element types of typed relations |
product.ts:185,238 |
(f: any) |
Row<skuFeatures> |
|
product.ts:596 |
(tag: any) |
inferred (cast at 594) | |
product.ts:598,669,709 |
(assignment: any) |
Row<productTags> & { sku: … } |
|
product.ts:756 |
(review: any) |
inferred select shape | |
product.ts:817,822 |
(group:any), (membership:any) |
inferred | |
product.ts:367 |
updateProduct(id, input: any) |
UpdateProductInput (domain) |
|
product.ts:39,41,114,340,498,545 |
any[]/(ci:any) |
CreateComboItemInput / AdminProductComboItem[] |
|
product.ts:384,398,401 |
(sku: any) |
CreateSkuInput & { id?: number } |
|
product.ts:956 |
const updateData: any |
Partial<Insert<productMarketStats>> |
|
sqlite/admin-apis/order.ts:174,239,250,364,369,378,388,412,523,528,538,549,554,577,615,616,622,643 |
(u|item|f|order|acc: any) |
delete → inferred | typed query results |
sqlite/admin-apis/slots.ts:122,125,133,199 |
(item|s|sku: any) |
delete → inferred | |
slots.ts:194 |
(item: any) + reads item.isDeleted |
inferred; add isDeleted: true to columns at :191 |
hidden bug surfaced by typing |
slots.ts:56 |
fetchExistingSkuIds(tx: any, …) |
Drizzle tx type (Parameters<Parameters<typeof db.transaction>[0]>[0]) |
|
stores/store-helpers.ts:312,315,326 |
(item|s|sku: any) |
delete → inferred | |
admin-apis/store.ts:7,17 (both pkgs) |
Promise<any[]> / Promise<any|null> |
Array<Row<storeInfo> & { owner: Row<staffUsers>|null }> |
|
admin-apis/staff-user.ts:22,78 (both) |
Promise<any[]> |
inferred relation / StaffRole[] |
|
admin-apis/user.ts:5,28,95,122,184,224,245 (both) |
Promise<any…> |
Row<users>, Pick<Row<users>,…>, Row<userIncidents>, etc. |
select shapes |
admin-apis/coupon.ts:10,53,175,211,213,300 (both) |
any[]/Promise<any…>/input: any |
Row<coupons> & {…}, Row<reservedCoupons>, ReservedCouponInput |
InferInsertModel |
user-apis/auth.ts:102,119 (both) |
const userUpdate: any |
Partial<Insert<users>> / Partial<Insert<userDetails>> |
|
user-apis/auth.ts:184 (both) |
catch (error: any) |
unknown + narrow |
23505 is pg-only |
lib/run-batched.ts:3,19 |
(cb: (tx: infer Tx) => any, ...args: any[]) => any |
unknown |
unused callback return/args |
lib/automated-jobs.ts:25 (both) |
value: any |
unknown |
Easy wins: delete : any from ~60 map/filter callbacks; run-batched any→unknown; automated-jobs value: unknown; object literals → Partial<Insert<…>>; catch→unknown; free bug fix at slots.ts:191/194; ~35 Promise<any> return annotations via Row/Insert.
apps/admin-ui
Summary: 161 code occurrences / 49 files. Top: delivery-sequences/index.tsx (10), prices-overview (11), products/add+edit (14), _layout.tsx (13). Dominant: catch/onError (error: any) (35) and router.* as any (36) — both mechanical.
| Location | Current code | Should be | Why |
|---|---|---|---|
_layout.tsx:53…137, dashboard/index.tsx:32,99,242, banners/products/slots/stores/prices/manage-orders (≈18 files) |
router.push("…" as any) |
as Href (expo-router); drop cast for static routes |
typed routes |
dashboard/index.tsx:39,250,275, manage-orders/index.tsx:77 |
name={item.icon as any} |
keyof typeof MaterialIcons.glyphMap |
glyph union |
TagMenu.tsx:62, stores/edit:28, send-notifications:48, coupons/*, prices:286, SlotForm:92,107, delivery-sequences, order-details, orders (≈24) |
onError: (error: any) |
delete annotation | tRPC infers |
| VendorSnippet/ProductGroupForm/products/coupons/stores/vendor-snippets/product-tags/send-notifications (≈11) | catch (error: any) |
unknown + narrow |
|
coupons/index.tsx:11,111 |
item: any |
Coupon & {relations} / reserved (domain) |
backend returns any[] |
stores/index.tsx:15 |
item: any |
Store |
|
products/index.tsx:148 |
{ item: any } |
Omit<AdminProductWithRelations,'skus'> & { skus: SerializedAdminSku[] } |
|
slots/index.tsx:11, rebalance-orders:10 |
item: any |
AdminSlotWithProducts |
|
slots/slot-details.tsx:24, product-groupings:130, products/detail:146 |
useState<any…> |
AdminSlotProductSummary[], AdminSku[], AdminProductReviewWithSignedUrls |
|
slots/index:238, rebalance:123 |
useState<any[]> |
string[] |
product names |
products/add:15,64,29,36,80, edit (same) |
values: any, (variant:any), (a:any), (ci:any) |
ProductFormData, Variant, Attribute, CreateComboItemInput (export from ProductForm) |
|
BannerForm:66, StoreForm:72, products/detail:32 |
setFile: async (assets: any) |
ImagePicker.ImagePickerAsset | ImagePickerAsset[] |
|
TagForm.tsx:40 |
forwardRef<any,…> |
unknown |
no imperative handle |
TagForm.tsx:57 |
(sku: any) |
SkuSummary |
|
toaster.tsx:39 |
data: any |
{ rideId?; carId? } | null (domain) |
|
CouponForm.tsx:60,66,156,191,192,205,237,238 |
function(value:any), (values as any), (errors.couponCodes as any) |
CouponFormValues, narrow error shapes |
|
ProductGroupForm:13, SnippetOrdersView:21, SlotForm:37,48,191 |
products: any[], sequence: any[], (snippet/p: any) |
AdminSku[], number[], AdminVendorSnippetWithAccess, AdminSlotProductSummary |
|
UserIncidentsView:141 |
(incident: any) |
UserIncident (domain) |
|
customize-app/index:9,58,59,60 |
Record<string,any>, value:any, setFieldValue(any), router:any |
Record<string,unknown>, unknown, Router |
|
popular-items:139, all-items-order:111, product-tags/order:102 |
value.map((id: any) => parseInt(id)) |
number (root: Constant.value) |
|
prices-overview:25,28,29,30,46,153,204,224,270 |
sku:any, Record<string,any>, const update:any |
local PriceSku, existing PendingChange, mutation input |
|
delivery-sequences:53,354,373,389,438,588,622 |
orders:any[], (deliverySequence as any) |
AdminSlotOrder[], drop cast (AdminDeliverySequence) |
|
order-details:148 |
const mutationData:any |
initiateRefund input |
|
coupons/create:27 |
values: any |
CouponFormValues |
Easy wins: drop : any on 24 onError; catch→unknown (11); as any→as Href (36); icon glyph types (4); drop deliverySequence as any (6); remove products/edit:180 as any; triggerStyle → StyleProp<ViewStyle>; export ProductFormData/Variant/Attribute.
apps/user-ui + apps/fallback-ui
Summary: 137 real type-level / 46 files (4 non-type "any" words ignored). Top: home/index.tsx (20), cart-page (11), ProductDetail (11). Dominant: catch/onError (29); router casts (23); catalog/cart item: any (30+).
| Location | Current code | Should be | Why |
|---|---|---|---|
| login/register/edit-profile/ComplaintForm/OrderMenu/ProductDetail/registration-form + fallback create-coupon/demo | catch (error: any) |
unknown + narrow |
|
many onError: (error: any) (14+) |
onError: (error: any) |
unknown / delete (tRPC infers) |
|
me/index, SlotSpecificView, cart-page (≈12) |
router.replace/push(target as any) |
Href |
|
| fallback AuthWrapper/home/login/super-admin/user-home (≈13) | navigate({ to: '…' as any }) |
drop cast | routes registered |
me/index:137, my-orders:111,278 |
icon as any |
ComponentProps<typeof Ionicons/MaterialIcons>['name'] |
|
my-orders:68,69 |
getStatusColor(): any |
typed StatusColor |
|
home/index.tsx (many) |
slot: any, (p: any), dashboardTags:any[], Record<number,any[]>, useRef<any>, onLayout(e:any), useState<any[]> |
UserSlotWithProducts, UserSlotProduct, AllProductsApiType['tags'], MergedProduct[], ComponentRef<typeof ScrollView>, LayoutChangeEvent |
catalog types exist |
ProductDetail:48,75,76,79,87,147,710 |
useState<any[]>, (slot/p/a/b/item:any), setFile(assets:any) |
review/cart/slot types + ImagePickerAsset |
shared UserProductReviewWithSignedUrls missing adminResponse/signedAdminImageUrls (domain) |
cart-page:60 |
coupon: any |
UserCouponWithRelations |
|
registration-form:29 |
useState<any> |
ImagePicker.ImagePickerAsset |
|
useUploadToObjectStore:26 |
contextString as any |
drop cast | shared ContextString assignable |
notif-context:45,46 |
useRef<any> |
listener return types | |
toaster:5 |
data: any |
Record<string, unknown> |
|
AddToCartDialog (6) |
(item/slot/p: any), Record<number,any> |
CartItem, UserSlotWithProducts, UserSlotProduct |
|
AuthContext:14 |
Record<string,any> |
tighten shared AuthRedirectOptions.queryParams |
|
getCurrentUserId:8 |
jwtDecode(token) any |
jwtDecode<{id?;userId?}> |
|
fallback order-details:33,51,223, user-details:44,45,141, login:23, demo:11,76, inauguration:74 |
as any / any[] / any |
AdminOrderDetails, inferred, ReturnType<typeof setInterval>, local DemoResponse |
|
ProductCard:22,29,84,93,94 |
item:any, ComponentType<any>, (cartItem:any), Record<number,any>, (slot:any) |
MergedProduct, ComponentType<PropsWithChildren>, CartItem, UserSlotWithProducts |
|
SlotSpecificView:232,252,457 |
item:any, (cartItem:any), (p:any) |
MergedProduct, CartItem |
|
PaymentAndOrderComponent:17,24,25 |
cartItems:any[], constsData:any, selectedCoupons:any[] |
CartItem[], EssentialConstsApiType, EligibleCoupon[] |
|
hooks/useProductSlotIdentifier:18,25, prominent-api-hooks:127 |
(slot/a/b/p: any) |
drop → inferred |
Easy wins: bulk unknown (29); delete fallback as any casts (≈18 incl. contextString); catalog/cart annotations (≈30) → MergedProduct/CartItem; icon types (4); trivial typed anys (jwt, setInterval, notif refs, toaster, styles).
apps/web-ui
Summary: 138 annotations / 35 files (2 prose excluded). Top: slot-view (20), home.index (18), flash (10), home.product.$id (9). Dominant: untyped list callbacks over cached API data (MergedProduct, UserSlotWithProducts), then (error: any).
| Location | Current code | Should be | Why |
|---|---|---|---|
FloatingCartBar:43,44, PaymentAndOrderComponent:34,35, cart:18,19, checkout:38,39, home.cart:18,19 |
Record<number,any> / (p:any) |
Record<number, MergedProduct> / (p: MergedProduct) |
from useAllProducts() |
AddToCartDialog:45,78, ProductCard:38, home.product.$id:63, flash:205 |
(item:any) |
CartItem |
useGetCart() |
slot-view:399 |
(cartItem:any).productId |
(cartItem: CartItem).skuId |
latent bug |
AddToCartDialog:53,57,59,143, usePopulateCentralStores:15,30,31,43, home.product.$id:51,52,55,94,316,397, slot-view:58…153, home.index:623 |
(slot:any), slot.products.forEach((p:any), slot maps, (a/b:any) |
UserSlotWithProducts, UserSlotProduct, Record<number, UserSlotWithProducts> |
useSlots() |
usePopulateCentralStores:15 (+43–48) |
extra fields deliveryDate/displayDate/displayTime |
domain: not on UserSlotWithProducts but required by SlotInfo |
stale/dead-field mismatch |
usePopulateCentralStores:25 |
Record<number,any> |
ProductSlotMap[number] (export) |
|
flash:38,67,77,83,166, home.index:154,155,225,326, home.search:87,166, offers:32,67,68, slot-view:139…238, stores.$storeId:44,125,163, usePopulateCentralStores:28, prominent-api-hooks:167 |
(product/p/a/b:any) |
MergedProduct |
|
stores.$storeId:28,38 |
new Map<number,any>, (product:any) |
Map<number, MergedProduct>, (product: UserStoreProduct) |
|
home.index:133,135,142,143 |
Record<number,any[]>, Map<number,any>, const ordered/rest: any[] |
MergedProduct[] etc |
|
ProductCard:11 |
item:any |
MergedProduct |
|
flash:36,54,124,156, home.index:378,530, slot-view:228,294,339, stores:78,104, stores:161 |
(store:any), stores:any[], (product:any) |
UserStoreSummary, UserStoreSampleProduct |
|
checkout-hooks:16,44,67, CheckoutAddressSelector:11,72, checkout:31, flash.checkout:74, home.checkout:75 |
useState<any>, (addr/address:any) |
UserAddress |
|
AddressForm:48,59,90,92, MeOrderMenu:68,95, PaymentAndOrderComponent:67, me.addresses:121,149, me.edit-profile:46,56,103, me.orders.$id:42,54 |
onError/catch (e:any), (error:any) |
delete / unknown; AddressForm narrow Yup.ValidationError |
|
me.orders.$id:99 |
order as any |
drop (UserOrderDetail) |
|
me.orders.$id:117,301, me.orders:189,75,325 |
(item/product:any), useState<any[]> |
UserOrderItemSummary, UserOrderSummary |
|
BottomNavigation:72, Sidebar:81, me:167 |
to: … as any |
generated route union | |
Topbar:27 |
'/home/search' as any |
drop cast | |
home.index:122,291,472,474,513 |
(t/tag/b/_:any), banners:any[] |
tag type, UserBanner, string |
|
home.product.$id:379 |
(deal:any) |
SpecialDealCore |
|
lib/auth-context:15,24,110 |
userDetails:any, (details:any) |
local User |
|
flash-cart-store:4,5 |
any | null |
MergedProduct | null (domain) |
|
useUploadToObjectStorage:26 |
contextString as any |
drop | |
ProductCard:47,48, PaymentAndOrderComponent:13, slot-view:101,104, me.complaints:168 |
Record<number,any>, (slot:any), cartItems:any[], as any time, (complaint:any) |
SlotInfo, CartItem[], widen helper, UserComplaint |
Easy wins: drop redundant annotations on tRPC onError (10) and cartData.items.find (5); replace 5-file productsById boilerplate (10); catch→unknown (4); export CartItem + SlotInfo/ProductSlotMap; drop navigate casts; fix slot-view:399 bug.
apps/admin-web
Summary: 128 annotations (3 prose excluded) / 50 files. Top: orders.sequence (11), prices (10), products.edit (9). Dominant: onError/catch (36 = 28%), untyped rows, route casts.
| Location | Current code | Should be | Why |
|---|---|---|---|
24 sites (stores.edit:35, orders.sequence:471,623,665, orders.list:71,171, coupons.*, slots:51, complaints:81, SlotForm:91,106, notifications:35, TagMenu:56, UserIncidentsView:31, staff-auth:62, orders.$id:68,84,95,105, CancelOrderDialog:34, prices:281, stores.new:27) |
onError: (error:any) |
delete | tRPC infers |
13 sites (product-tags.new:50, product-tags.edit:65, coupons.new:57, products.$id:81, notifications:72, vendor-snippets:54,296, OrderOptionsMenu:69, products.new:106, ProductGroupForm:68, VendorSnippetForm:87, products.edit:189, stores:114) |
catch (error:any) |
unknown + narrow |
|
orders.sequence:363,382,398,456,603,635 |
(deliverySequence as any) |
drop → AdminDeliverySequence |
|
slots.$id.edit:48, slots:28, rebalance:28, slots.new:43, SlotForm:47 |
(p:any) |
AdminSlotProductSummary |
|
SlotForm:36 |
(snippet:any) |
AdminVendorSnippetWithAccess (shape mismatch, domain) |
|
SlotForm:189, TagForm:114, prices:41 |
(prod/sku/f:any) |
AdminSku, SkuSummary, AdminSkuFeature |
|
product-tags.edit:92 |
(p:any) |
AdminProductTagAssignment |
|
ProductGroupForm:12, product-groupings:25,108 |
products:any[], useState<any[]> |
AdminSku[] |
|
UserIncidentsView:142 |
(incident:any) |
UserIncident (domain) |
|
products:149 |
(product:any) |
AdminProductWithRelations |
|
rebalance:13, slots:14 |
item:any |
AdminSlotWithProducts |
|
rebalance:16,128, slots:15,242 |
Dispatch<…any[]>, useState<any[]> |
string[] |
|
slots.detail:31 |
useState<any[]> |
domain (AdminSlotProductSummary lacks shortDescription) |
|
orders.sequence:69 |
orders:any[] |
AdminSlotOrder[] |
|
prices:20,23,24,25,148,199,219,265 |
sku:any, Record<string,any>, const update:any |
SkuRow, existing PendingChange, mutation input |
|
vendor-snippets:233 |
useState<any> |
{ orders; snippetCode } (align totalAmount number/string) |
|
SnippetOrdersView:20 |
sequence:any[] |
unknown/number[] |
shared is unknown |
coupons.new:30, products.edit:87, products.new:19 |
values: any |
export CouponFormValues / ProductFormData |
|
CouponForm:78,84,171,206,207,220,252,253 |
function(value:any), (values as any), (errors as any) |
CouponFormValues, narrow |
|
coupons.tsx:14,17,114,220,363 |
item/coupon:any |
Coupon & {relations} / reserved (domain) |
|
MultiSelect:25, SearchableSelect:23, coupons:302,430 |
triggerComponent?: any |
(props:{onClick:()=>void}) => ReactNode |
|
SnippetMenu:20, TagMenu:11 |
triggerStyle?: any |
string | CSSProperties |
|
TagForm:96 |
forwardRef<any,…> |
unknown (ref unused) |
|
customize-app:12,61,62,63 |
Record<string,any>, value:any, setFieldValue(any), router:any |
Record<string,unknown>, unknown, local router shape |
|
customize-app.ordering:113, popular:126, product-tags.order:106 |
value.map((id:any)=>parseInt(id)) |
root: Constant.value |
|
stores.edit:33, dashboard.index:82, customize-app:173, orders.tsx:24, dashboard.tsx:108 |
navigate({to: … as any}) |
generated route union / drop | |
products.edit:66,101,108,139,162,166,183, products.new:33,40,68,84,88 |
(variant/ci/a/attr:any), as any |
Variant, AdminProductComboItem, SkuFeatureLike, CreateComboItemInput |
|
orders.$id:159 |
const mutationData:any |
initiateRefund input |
|
toaster:16, event-bus:6,11 |
_data:any, ...args: any[] |
unknown |
Easy wins: drop 23 onError; 13 catch→unknown; type slot rows (9); prices SkuRow+PendingChange (10); export ProductFormData/Variant/Attribute/CouponFormValues; fix shared Constant.value; typed routes (5).
packages/shared + web-components + ui + migrator
Summary: 28 tokens / 17 files. Top: app-common.types.ts (5), migrator/sqliteToPostgres (4), web-components/data-table.tsx (4). Dominant: untyped component props + RN style/asset props. (No catch (e: any) in scope.)
| Location | Current code | Should be | Why |
|---|---|---|---|
packages/shared/types/app-common.types.ts:20 |
queryParams?: Record<string, any> |
Record<string, unknown> |
only String(value) |
app-common.types.ts:60 |
item: any |
generic ListItemProps<T> (domain) |
shared list renderer |
app-common.types.ts:78 |
item: any |
hoist shared product type (domain) | consumers use id/images/name/flashPrice/incrementStep |
app-common.types.ts:87 |
products: any[] |
shared product type (domain) | offers section |
app-common.types.ts:96 |
product: any |
shared product type (domain) | AddToCartDialog |
packages/shared/types/const.types.ts:8 |
value: any |
ConstValueType | ConstValueType[] (defined line 18) |
consumers branch/narrow |
migrator/sqliteToPostgres/index.ts:47 |
.all() as any[] |
named SqliteColumnRow |
PRAGMA shape fixed |
migrator/.../index.ts:113 |
parseValue(value:any): any |
unknown |
returns JSON.parse/raw |
migrator/.../index.ts:181 |
.all() as any[] |
Record<string, unknown>[] |
dynamic SELECT * |
packages/ui/src/services/axios.ts:56 |
(err as any).original = error |
Object.assign / typed Error & { original: unknown } |
|
packages/ui/src/lib/refresh-context.tsx:7 |
queryClient: any |
QueryClient |
dep exists |
packages/ui/src/lib/tailwind.ts:6 |
create(tailwindConfig as any) |
as TwConfig (twrnc) |
|
packages/ui/src/components/image-viewer.tsx:16 |
style?: any |
StyleProp<ImageStyle> |
|
packages/ui/src/components/info-dialog.tsx:15, dropdown.tsx:17 |
style?: any |
StyleProp<ViewStyle> |
|
packages/ui/src/components/search-bar.tsx:21 |
forwardRef<any,…> |
React.ElementRef<typeof PaperTextInput> |
|
packages/ui/src/components/text.tsx:25 |
let fontWeight: any |
TextStyle['fontWeight'] |
|
packages/ui/src/components/profile-image.tsx:11,25 |
file?: any, setFile:(file:any) |
ImagePickerAsset & { name } |
|
packages/ui/src/components/use-pick-image.tsx:13 |
setFile: (file: any) => void |
ImagePickerAsset | ImagePickerAsset[] | null |
root of many assets: any |
packages/ui/src/components/ImageUploaderNeo.tsx:22 |
(files: any) |
ImagePickerAsset | ImagePickerAsset[] | null |
|
packages/ui/src/components/ImageCarousel.tsx:27 |
(event: any) |
NativeSyntheticEvent<NativeScrollEvent> |
|
packages/web-components/.../my-text-input.tsx:45 |
{...(props as any)} |
TextareaHTMLAttributes union |
spread onto <textarea> |
packages/web-components/.../data-table.tsx:7,12,13 |
(value:any,row:any), data:any[], (row:any,index) |
generic Column<T> / DataTableProps<T>, T extends Record<string, unknown> |
Easy wins: queryParams/Constant.value; migrator unknown + typed PRAGMA row; QueryClient/TwConfig; RN prop types (10); Object.assign; make DataTable generic. 4 domain items: product-shaped props in app-common.types.ts.
Suggested remediation order
- Mechanical, huge payoff (~200 sites, no domain knowledge):
catch/onError→unknown; delete tRPConErrorannotations;Record<string, any>→unknown;z.any()→z.unknown(); delete: anyfrom typed Drizzle callbacks. - Shared root causes (removes dozens downstream):
Constant.value,app-common.types.ts,use-pick-image.tsx, exportCartItem/SlotInfo/MergedProductandProductFormData/CouponFormValues. - Backend result typing: replace
Promise<any…>db-helper returns andany[]procedures withInferSelectModel/shared types — unblocks both admin frontends. - Typed routes: Expo
Href/ TanStack generated union (removes ~50as any). - Domain-input types to define:
UserIncident, reserved-coupon/client-coupon-with-relations,RefundInput, shared product type,NotificationToastpayload. - Bugs masked by
any(fix while typing):web-ui/src/routes/slot-view.tsx:399(cartItem.productId→skuId),db_helper_sqlite/src/admin-apis/slots.ts:191/194(isDeletednot selected),usePopulateCentralStores.ts:15(deliveryDate/displayDate/displayTimefields not on the slot type).