DedSec Project

TS2322 — DedSec Project

TS2322 — a value violates the declared TypeScript contract Root cause TS2322 reports that one type cannot be assigned to another, for example a textual amount where a numeric amount is…

TS2322 — a value violates the declared TypeScript contract

Root cause

TS2322 reports that one type cannot be assigned to another, for example a textual amount where a numeric amount is required. The compiler does not perform parsing automatically because '12', '12x', an empty string and an overflowing number are distinct runtime inputs. A type assertion with as number only tells the compiler to trust you; it cannot convert text to a number at runtime.

Reliable fix

Use a boundary function accepting unknown input, check that the value is a digit-only string and convert it with Number. Reject unsafe integers before creating a typed Entry. The production model stores integer cents, not float amounts, and the compiler checks downstream use of that model.

Verified TypeScript example

type Entry = { id: string; cents: number };
function parseCents(value: unknown): number {
  if (typeof value !== 'string' || !/^(0|[1-9][0-9]*)$/.test(value))
    throw new TypeError('expected nonnegative integer cents as text');
  const amount = Number(value);
  if (!Number.isSafeInteger(amount)) throw new RangeError('outside safe integer range');
  return amount;
}
const entry: Entry = {id: 'sample', cents: parseCents('150')};
if (entry.cents !== 150) throw Error('bad conversion');
console.log('PASS TS2322');

Why it works

TypeScript types disappear after compilation. The regular expression deliberately bans leading-zero noncanonical amounts and negative values for this specific exercise; other domains may need a different contract. Number.isSafeInteger excludes integer values that cannot be represented exactly as IEEE-754 doubles. For very large quantities, BigInt or validated decimal storage may be appropriate.

Reproduction and build commands

Save as main.ts. Run tsc --strict --target es2022 --module commonjs --outDir dist main.ts && node dist/main.js. Expected PASS. In a separate bad.ts, write const cents: number = '100'; and confirm tsc --strict --noEmit bad.ts emits TS2322. Do not include an intentionally failing file in the normal build.

Diagnostics to practice

Try the values '0', '01', '10.5', '-1', 'abc' and '9007199254740992'. Predict rejection before executing. Compare Number('') with the guarded converter and explain why blind numeric coercion loses input validation. Use satisfies to check object literals without relying on unsafe casts.

Reference: https://www.typescriptlang.org/docs/handbook/2/everyday-types.html