TypeScript Strict Mode — independently scanned and version-tracked by SaferSkills.
SaferSkills independently audited TypeScript Strict Mode (Agent Skill) and scored it 100/100 (green). The audit ran 55 deterministic rules across Security, Supply Chain, Maintenance, Transparency, and Community; it found 0 high-severity and 0 lower-severity findings. The full rule-by-rule trace and per-finding evidence are below. Free, methodology-open.
Findings & checks · 0 flagged
Every scanned point with the score it earned and what moved between them.
First recorded scan — no prior version to compare against.
The primary manifest — the file an agent reads to learn what this artifact does.
Every any is a runtime bug that the compiler was ready to catch and was told not to. Strict TypeScript converts a class of production failures - undefined access, wrong-shape API responses, unhandled union cases - into compile errors that cost seconds instead of incidents. This skill enforces strictness in new code and migrates existing loose codebases without a big-bang rewrite.
"strict": true is the floor, not the ceiling - noUncheckedIndexedAccess and exactOptionalPropertyTypes catch real bugs that strict alone misses.Before migrating or reviewing, gather: (1) the current tsconfig, (2) whether the codebase is greenfield or existing - and if existing, the error count per flag (tsc --noEmit after toggling each flag tells you), (3) any third-party libraries with missing or bad types, since those are where casts concentrate. If the error counts are unknown, measure them first; label any estimate a guess.
{
"compilerOptions": {
"strict": true, // enables all strict-family checks
"noUncheckedIndexedAccess": true, // arr[i] and obj[key] are T | undefined
"exactOptionalPropertyTypes": true, // { a?: string } rejects { a: undefined }
"noImplicitOverride": true,
"noImplicitReturns": true,
"noFallthroughCasesInSwitch": true,
"noUnusedLocals": true,
"noUnusedParameters": true,
"forceConsistentCasingInFileNames": true
}
}any - use unknown and narrow, or define the type.as SomeType on values from outside the type system - use type guards or schema validation instead.value!.property non-null assertion - handle null/undefined explicitly.@ts-ignore - fix the error. If suppression is truly unavoidable, @ts-expect-error with a reason comment, which errors when the underlying problem is fixed.any in function parameters.unknown over any for truly unknown data, then narrow.satisfies over as when checking a value against a type without widening it.as const assertions for literal types.never check in the default case.Bad - any erases checking downstream:
function parse(json: string): any { return JSON.parse(json) }
const user = parse(body); user.emial // typo compiles, crashes laterGood - unknown forces proof before use:
function parse(json: string): unknown { return JSON.parse(json) }
const data = parse(body)
if (isUser(data)) { data.email } // typo is a compile errorBad - assertion claims without evidence:
const user = JSON.parse(body) as User // wrong shape crashes at runtimeGood - narrowing proves the shape:
function isUser(x: unknown): x is User {
return typeof x === 'object' && x !== null && 'id' in x && 'email' in x
}Good - exhaustive switch that breaks the build when a variant is added:
function handle(action: Action) {
switch (action.type) {
case 'A': return handleA(action)
case 'B': return handleB(action)
default: { const _exhaustive: never = action; throw new Error('unreachable') }
}
}Order matters: each flag builds on the previous one's guarantees, and the noisiest flags come last so early wins build momentum.
noImplicitAny. Fix by adding real types, not : any. This is the highest-value flag per error fixed.strictNullChecks (with strictFunctionTypes and alwaysStrict). Usually the largest error count. If a flag produces more errors than the team can fix in about two weeks, scope it per-directory with project references or a second tsconfig, and ratchet the boundary weekly - never let an "errors allowed" list grow.strictBindCallApply, strictPropertyInitialization, useUnknownInCatchVariables), then replace the individual flags with "strict": true.noUncheckedIndexedAccess, then exactOptionalPropertyTypes. These are last because they are the noisiest and the fixes (index checks, undefined-vs-absent distinctions) are mechanical once the codebase is null-safe.@ts-expect-error you can after each step; each one still standing needs a reason comment.A cast is acceptable only at a boundary the type system cannot see across: deserialized JSON, a third-party library with wrong types, a test fixture. Contain it:
as unknown as T double assertions only in test code, never in production paths.@ts-expect-error over @ts-ignore, always with a description.Produce strict-compliant code plus, for migrations, a flag-by-flag plan: current error count per flag, the enablement order above, the per-directory scoping if any count exceeds the two-week budget, and the CI ratchet that blocks new violations immediately.
any or adding ! - that converts a found bug back into a hidden one.as to satisfy the compiler on data from outside the process - validate, then narrow.noUncheckedIndexedAccess because it is noisy; unchecked index access is the single most common strict-mode blind spot.tsc --noEmit passes with the target config (or the migration plan states exactly which flags are pending and their error counts).any, zero @ts-ignore, zero bare non-null assertions in the changed code.never exhaustiveness check.~30 seconds. Free. No account. Every finding cites a rule and a line of evidence.