2
I fixed a type-safety hole in TypeScript — fewer params in interface implementation now errors go javascript typescript
by topce 24 days ago | 0 comments

TypeScript's type checker has a blind spot: if you implement an interface with fewer
parameters than declared, it compiles silently. I added a check that rejects it.

The problem:

interface Door {
open(key: string, code: number): void
}

class MyDoor implements Door {
open(key: string) { }
// compiles in TypeScript, no error
}

The reasoning in TypeScript is that functions are free to ignore extra arguments —
that's intentional for callbacks like array.map((value, index) => ...) where you
often omit index. But for interface/class method implementations, this isn't a
callback pattern — it's a contract. If the interface says open takes two arguments,
a class claiming to implement it should match that arity.

The fix is 22 lines added to internal/checker/relater.go in microsoft/typescript-go:

var sourceHasFewerParameters bool
// Only check for fewer parameters when comparing interface/class method
// implementations, not for function assignments or callback functions.
if checkMode&SignatureCheckModeCallback == 0 &&
(kind == ast.KindMethodDeclaration ||
kind == ast.KindMethodSignature ||
kind == ast.KindConstructor ||
kind == ast.KindConstructSignature) {
if !c.hasEffectiveRestParameter(source) {
if checkMode&SignatureCheckModeStrictArity != 0 {
sourceHasFewerParameters = c.hasEffectiveRestParameter(target) ||
sourceCount < targetCount
} else {
sourceHasFewerParameters = sourceCount <
c.getMinArgumentCount(target)
}
}
}
if sourceHasFewerParameters {
if reportErrors && (checkMode&SignatureCheckModeStrictArity == 0) {
errorReporter(
diagnostics.Target_signature_provides_too_few_arguments_Expected_0_or_more_but_got_1,
sourceCount, c.getMinArgumentCount(target))
}
return TernaryFalse
}

Key design decisions:

  • The check is scoped to method/constructor signatures only, not function assignments
    or callbacks, so (x, y) => void accepting (x) => {} still works as before.
  • Optional parameters in the target are counted correctly via getMinArgumentCount,
    so m(x, y?) implemented by m(x) {} still compiles.
  • It mirrors the existing --strict family of checks in spirit — off by default,
    opt-in via SignatureCheckModeStrictArity, or enforced directly in the npm build.

Shipped as @topce/native-preview v7.0.0-dev.20260711.3:
https://www.npmjs.com/package/@topce/native-preview/v/7.0.0-dev.20260711.3

Patch against microsoft/typescript-go — relater.go, +22 lines, no deletions.

Curious if others have hit this in production. I've seen it cause silent API mismatches
between interface contracts and implementations a few times.