defineProps<T extends Record<string, unknown>> rejects an interface. A TypeScript interface has no implicit index signature, so it does not satisfy Record<string, unknown>; a type alias does.
This is the pattern the Stacks framework scaffolds. storage/framework/defaults/ declares props with interface 44 times and with type zero times.
Repro
<script server>
import { defineProps, withDefaults } from '@stacksjs/stx'
interface ValueCardProps {
icon: string
title: string
description: string
}
const { icon, title, description } = withDefaults(defineProps<ValueCardProps>(), {})
</script>ValueCard.stx:11:51 error TS2345 Argument of type 'ValueCardProps' is not assignable to parameter of type 'Record<string, unknown>'.
ValueCard.stx:11:63 error TS2344 Type 'ValueCardProps' does not satisfy the constraint 'Record<string, unknown>'.Change interface ValueCardProps { to type ValueCardProps = { and nothing else:
Checked 1 script block(s) and 3 template expression(s) in 1 file(s) — 0 error(s), 0 warning(s)Why nobody has hit it
Two things hide it.
The docstring only shows the inline form. Every example in props.d.ts is defineProps<{ title: string }>(). An inline object literal is assignable to Record<string, unknown>, so the documented usage passes. The error appears only when the type is extracted and named — which is what you do as soon as it is reused, documented, or exported.
The import usually does not resolve. Apps write import { defineProps } from 'stx'. There is no stx package, no declare module 'stx', and no path mapping in the app templates — so the module is any, the constraint is never enforced, and the component silently type-checks. In one real app, fixing the specifier turned 18 Cannot find module 'stx' errors into 36 constraint errors across 18 components. The bug was fully masked until the import was corrected.
Worth noting the specifier is itself split upstream: stx's own docs/ and packages/stx/test/ are 116 @stacksjs/stx vs 114 stx, while storage/framework/defaults/ is 39-to-0 in favour of @stacksjs/stx. Apps copying from docs get a coin flip.
Fix
<T extends object> accepts both an interface and a type alias, and still rejects primitives — which is all the constraint needs to do here. definePropsWithValidation and any other helper with the same constraint want the same change.
Separately worth deciding whether stx should resolve at all — either ship it as an alias, or make the docs consistently say @stacksjs/stx. Right now the broken half of the docs is what keeps this bug invisible.