Problem
The published @nimiq/mini-app-sdk@0.0.2 returns errors as a non-discriminated union:
listAccounts(): Promise<string[] | ErrorResponse>;
sign(message: ...): Promise<SignatureResult | ErrorResponse>;
sendBasicTransaction(tx: ...): Promise<string | ErrorResponse>;
// ...same shape for sendBasicTransactionWithData, sendNewStakerTransaction,
// sendStakeTransaction, sendSetActiveStakeTransaction, sendUpdateStakerTransaction,
// sendRetireStakeTransaction, sendRemoveStakeTransaction
ErrorResponse is { error: { type: string; message: string } }. The success branch is the bare value (string[], string, SignatureResult).
TypeScript can narrow this via 'error' in result, but the natural patterns in JS are either thrown errors or a discriminated union with an explicit tag ({ ok: true; value } | { ok: false; error }). As written, every call site has to write the same runtime guard:
const result = await provider.listAccounts();
if ('error' in result) throw new Error(result.error.message);
const addresses = result; // typed as string[]
I wrote that guard once in PanoramicRum/nimiq-simple-faucet#113 so the rest of the example doesn't have to. Every Mini App that uses the SDK is paying this tax.
Suggested fix
Pick one and apply it consistently across every method:
- Throw on failure: success paths return the bare value, errors throw. Fits how every other modern JS API behaves; works with
try/catch and await.
- Discriminated union with explicit tag:
Promise<{ ok: true; value: T } | { ok: false; error: ErrorResponseBody }>. TS narrows on the ok field, no 'error' in runtime check, no thrown errors.
Either is fine. The current shape is the worst of both worlds — narrowing-by-shape always feels accidental and is easy to skip if the consumer doesn't have strict TS settings.
Document the chosen convention on the SDK reference page (see related issue).
Out of scope
The 0.0.2 → 1.0 migration is the right window for this. Once a Mini App ecosystem builds on 0.x with the current shape, you're stuck with it.
Found while building PanoramicRum/nimiq-simple-faucet#113.
Problem
The published
@nimiq/mini-app-sdk@0.0.2returns errors as a non-discriminated union:ErrorResponseis{ error: { type: string; message: string } }. The success branch is the bare value (string[],string,SignatureResult).TypeScript can narrow this via
'error' in result, but the natural patterns in JS are either thrown errors or a discriminated union with an explicit tag ({ ok: true; value } | { ok: false; error }). As written, every call site has to write the same runtime guard:I wrote that guard once in PanoramicRum/nimiq-simple-faucet#113 so the rest of the example doesn't have to. Every Mini App that uses the SDK is paying this tax.
Suggested fix
Pick one and apply it consistently across every method:
try/catchandawait.Promise<{ ok: true; value: T } | { ok: false; error: ErrorResponseBody }>. TS narrows on theokfield, no'error' inruntime check, no thrown errors.Either is fine. The current shape is the worst of both worlds — narrowing-by-shape always feels accidental and is easy to skip if the consumer doesn't have strict TS settings.
Document the chosen convention on the SDK reference page (see related issue).
Out of scope
The
0.0.2 → 1.0migration is the right window for this. Once a Mini App ecosystem builds on 0.x with the current shape, you're stuck with it.Found while building PanoramicRum/nimiq-simple-faucet#113.