As of v1.27.0 the @kensio/smartass npm package now exports
ESLint config rules
to encourage use of a more specific assertion when one is available.
For example, for slightly misused assertions like these:
assertIdentical(fooBool, true);
assertIdentical(fooList.length, 2);
assertTrue(typeof fooStr === "string");
The ESLint rules will highlight each with a warning and a suggestion to use a more appropriate assertion instead:
// ESLint: Use assertTrue(value) instead of assertIdentical(value, true).
// (no-restricted-syntax)
assertTrue(fooBool);
// ESLint: Use a more specific length assertion, such as
// assertArrayLength(value, expectedLength) or assertStringLength(value, expectedLength),
// instead of assertIdentical(value.length, expectedLength). (no-restricted-syntax)
assertArrayLength(fooList, 2);
// ESLint: Use a more specific type assertion, such as assertTypeString(value),
// assertTypeNumber(value), or assertTypeBoolean(value), instead of
// assertTrue(typeof value === expectedType). (no-restricted-syntax)
assertTypeString(fooStr);
This is useful for reminding human developers about better assertion options, and for improving on output from LLMs, which tend to overuse the more general assertion functions.
Using the more specific assertion functions allows a project to get more benefit from the type
narrowing effects in the @kensio/smartass library.
Some more examples of the replacements that the ESLint rules will suggest:
assertIdentical(value, true)→assertTrue(value)assertIdentical(value, false)→assertFalse(value)assertIdentical(value, undefined)→assertUndefined(value)assertTrue(value != null)→assertNonNullable(value)assertIdentical(typeof value, "string")→assertTypeString(value)assertIdentical(value instanceof MyClass, true)→assertInstanceOf(value, MyClass)assertIdentical("key" in object, true)→assertObjectHasProperty(object, "key")assertIdentical(value.length, expected)→assertArrayLength()etc.assertIdentical(value.size, expected)→assertSetSize()etc.assertTrue(array.length > 0)→assertArrayNotEmpty(array)assertTrue(value.includes(expected))→assertStringIncludes()etc.assertTrue(value.startsWith(prefix))→assertStringStartsWith(value, prefix)assertTrue(value.endsWith(suffix))→assertStringEndsWith(value, suffix)assertTrue(stats.isDirectory())→assertDirectoryExists()etc.
You can use the ESLint rules in your project’s eslint.config.ts like this:
import { defineConfig } from "eslint/config";
import tseslint from "typescript-eslint";
import { smartassPreferSpecificAssertions } from "@kensio/smartass/eslint";
export default defineConfig(
...tseslint.configs.recommended,
...smartassPreferSpecificAssertions,
);
And finally, a quick note on how the rules work internally. The rules use ESLint selector syntax to identify misused assertion functions. For example:
[{
selector:
"CallExpression[callee.name='assertIdentical'] > Literal[value=true]:nth-child(2)",
message:
"Use assertTrue(value) instead of assertIdentical(value, true).",
}]
CallExpression— look for a function call[callee.name='assertIdentical']— where the function being called is assertIdentical> Literal[value=true]— whose argument is the literaltrue:nth-child(2)— specifically the second argument
Note how this is similar to CSS selector syntax; it works in a similar way.