It's not exactly what you're asking for but Ur/Web puts an expressive type system to some slightly unusual ends: http://www.impredicative.com/ur/.
fun list () =
rows <- queryX (SELECT * FROM tab AS T)
(fn (fs : {T : $([Id = int] ++ map fst M.cols)}) => <xml>
<tr>
<td>{[fs.T.Id]}</td>
{@mapX2 [fst] [colMeta] [tr]
(fn [nm :: Name] [t ::_] [rest ::_] [[nm] ~ rest] v col => <xml>
<td>{col.Show v}</td>
</xml>)
M.fl (fs.T -- #Id) M.cols}
<td>
<a link={upd fs.T.Id}>[Update]</a>
<a link={confirm fs.T.Id}>[Delete]</a>
</td>
</tr>
</xml>);