JSX parses natively and passes through to .tsx untouched. React’s own type checking applies, jsxImportSource is read from your tsconfig, and every file may contain JSX. Hem supports expressions inside the braces:
let Badge = ({ state }: { state: PaymentState }) =>
<span className={match state {
| Paid(_) => "green"
| Refunded(_) => "red"
| _ => "gray"
}}>
{label(state)}
{if state == Pending { <Spinner size="sm" /> }}
</span>{if cond { <X/> }} is the conditional-rendering idiom: typed ?Element, and absent values render nothing. It replaces {cond && <X/>}, which boolean-only && forbids, preventing truthiness issues such as {items.length && ...} rendering a 0. Attributes also support unbraced forms: a bare name puns the in-scope binding, name? puns an optional, and simple values go unbraced:
<UserCard user compact subtitle?=bio onSelect=select(user.id) /><UserCard user={user} compact={compact} {...(bio === null || bio === undefined ? {} : { subtitle: bio })} onSelect={select(user.id)} />The optional pun lowers to a conditional spread rather than subtitle={undefined} on purpose: when the value is absent the prop is omitted, so exactOptionalPropertyTypes holds and React default props still apply.
<input checked /> passes your checked binding, not React’s implicit true. Write checked={true} for a literal boolean. Values with operators keep braces (JSX’s > and / are closing tokens); children are unchanged TSX: text by default, {} for expressions.