Ch. 2 · TypeScript

TypeScript Testing Public Type Contracts

TypeScript Testing Public Type Contracts. Learn the reasoning, a practical example, common mistakes and an interview exercise.

~2 min readadvancedupdated Oct 3, 2026

Type checks can verify that permitted usage compiles and invalid usage fails. These tests complement runtime tests because runtime success does not prove an API’s type constraints.

Before you start

You should be comfortable with JavaScript values, functions and objects. Use a TypeScript project with strict checking enabled when trying the examples. Separate what the compiler proves from what must still be checked when values arrive at runtime.

The practical goal is to reason through this situation: An expected-error fixture ensures UserId cannot be passed to an OrderId parameter. Read the walkthrough first, then try the interview exercise before opening its answer. The important part is explaining the decision and its consequences, rather than remembering a definition alone.

Step-by-step walkthrough

Step 1: Specify accepted usage

Write a compile-time fixture showing the intended inferred result. Runtime tests cannot establish that callers receive a useful static type.

Step 2: Specify rejected usage

Place an expected-error directive immediately before the intentionally invalid call. Keep the example narrow so an unrelated error cannot satisfy it unnoticed.

Step 3: Run the supported compiler

Check fixtures with the package’s strict options. When the API changes, investigate both newly accepted bad calls and newly rejected good calls.

Worked scenario

An expected-error fixture ensures UserId cannot be passed to an OrderId parameter.

function get<T, K extends keyof T>(object: T, key: K): T[K] {
  return object[key];
}
const count: number = get({ count: 3 }, 'count');
// @ts-expect-error unknown keys must stay rejected
get({ count: 3 }, 'missing');
TypeScript

The successful assignment protects numeric inference. The rejected call protects key constraints. If the error disappears, TypeScript reports the unused expected-error directive, making the regression visible.

Common mistake

An unmaintained suppression can hide unrelated failures if its surrounding code changes.

Verify the behavior

Temporarily loosen key to string and confirm the rejection fixture fails. Keep separate runtime checks for actual property-access behavior; type tests do not execute the function.

Interview exercise

Protect a generic helper’s inference.

Answer and reasoning

Include successful inference fixtures and targeted rejected calls; run them under the supported compiler configuration.

Continue learning

Compare the scenario with the TypeScript interview questions and test your understanding with the TypeScript MCQs. For terminology and implementation details, consult the reference material.

More in TypeScript

read ✓TypeScript · hard

TypeScript Abstract Classes and Contracts

Share behavior with abstract classes, enforce required members, and decide when an interface or composition is the better contract.

~2 min readread →
read ✓TypeScript · mid

TypeScript Enums vs Union Types

Compare enums with unions of string literals: runtime cost, serialization, exhaustiveness and which one fits application code.

~3 min readread →
esc