Async Patterns
Tsonic supports async workflows that can be lowered deterministically.
Supported direction
Promiseconstructionthen,catch, andfinally- supported
async/awaitflows - async callbacks when the delegate or handler shape is known
Typical examples:
- Promise-returning helper functions
- request/response flows in Node-style or ASP.NET Core code
- downstream application startup logic
Example:
export async function loadText(path: string): Promise<string> {
const value = await Promise.resolve(path);
return value.trim();
}
Where async usually goes wrong
- callback return type falls to
unknown - generic promise value loses enough context that the emitter cannot pick a stable lowered shape
- code relies on open-ended dynamic thenables instead of ordinary Promise-based flows
- control flow depends on dynamic import or other non-closed-world edges
Important rule
Async code still has to stay within the deterministic subset. The compiler does not keep implicit dynamic promise behavior just because TypeScript accepts it.
Practical advice
- annotate return types on exported async functions
- annotate callback returns when CLR overloads are involved
- prefer normal
Promise<T>flows over clever promise-like abstractions - debug async failures the same way you debug any other lowering issue: reduce to a small repro and inspect the generated output