ESLint Rules
Mikro.js ships @mikrojs/eslint-plugin, a set of ESLint rules that enforce the error handling conventions and catch patterns that don't work well on microcontrollers. The plugin is enabled by default in new projects.
Setup
Add the recommended config to your eslint.config.ts:
import mikrojs from '@mikrojs/eslint-plugin'
export default [...mikrojs.configs.recommended]This enables all rules below with their default severities.
Rules
@mikrojs/no-unhandled-result
Severity: error
Flags Result return values that aren't handled. If a function returns Result<T, E> or Promise<Result<T, E>> and the call expression isn't assigned to a variable or used in an expression, the error is silently lost.
// Bad: error is silently ignored
sensor.read()
// Good: error is checked
const result = sensor.read()
if (!result.ok) return result@mikrojs/no-throw
Severity: error
Flags throw statements. Expected errors should be returned as Result types. For truly unrecoverable situations, use panic() from mikro/sys.
// Bad
throw new Error('sensor failed')
// Good
return err(SensorError.ReadFailed('sensor failed'))
// Good (for unrecoverable situations)
panic('sensor hardware is missing')@mikrojs/no-try-catch
Severity: error
Flags try/catch blocks. Since Mikro.js functions return Result types, try/catch shouldn't be needed. try/finally for cleanup is allowed.
// Bad
try {
const value = sensor.read()
} catch (err) {
console.error(err)
}
// Good
const result = sensor.read()
if (!result.ok) {
console.error(result.error)
}
// Allowed (try/finally for cleanup)
try {
doSomething()
} finally {
cleanup()
}Standard JavaScript functions still throw: JSON.parse() on invalid input, atob() on a malformed string, decodeURIComponent() on invalid sequences. These aren't Mikro.js APIs and have no Result equivalent, so catching them is the correct thing to do. Disable the rule at the call site and convert to a Result immediately:
function parseJson(text: string): Result<unknown, {name: 'InvalidJson'}> {
// eslint-disable-next-line @mikrojs/no-try-catch -- JSON.parse has no Result form
try {
return ok(JSON.parse(text))
} catch {
return err({name: 'InvalidJson'})
}
}The same applies at a native module boundary, where a C function throws instead of returning a Result. See What about exceptions?.
@mikrojs/no-promise-reject
Severity: error
Flags Promise.reject() calls and reject() callback invocations. Use err() from mikro/result instead.
// Bad: caller has to try/catch to handle this
async function readSensor(): Promise<number> {
const result = sensor.read()
if (!result.ok) return Promise.reject(new Error('read failed'))
return result.value
}
// Good: caller sees the error in the return type
async function readSensor(): Promise<Result<number, GpioError>> {
const result = sensor.read()
if (!result.ok) return result
return ok(result.value)
}@mikrojs/no-dot-catch
Severity: error
Flags .catch() on promises. Async errors should be returned as Result types, not caught with .catch().
// Bad
fetchData().catch((err) => console.error(err))
// Good
const result = await fetchData()
if (!result.ok) console.error(result.error)@mikrojs/no-eval
Severity: error
Flags eval() calls and new Function() expressions. Runtime compilation is expensive on constrained devices and poses security risks.
@mikrojs/no-intl
Severity: error
Flags access to the Intl API. The Intl API is not available in QuickJS-NG. Use manual formatting or a lightweight library instead.
@mikrojs/no-temporal
Severity: error
Flags access to the Temporal API. The Temporal API is not available in QuickJS-NG. Use Date or a lightweight library instead.
@mikrojs/no-sparse-arrays
Severity: warn
Flags array literals with holes (for example [1,,3]) and delete on array elements. Use Array.prototype.splice() or filter instead.