TS2739: Type 'X' is missing the following properties from type 'Y': prop1, prop2, ... fires when you assign an object that lacks one or more required properties. Common when building objects piecewise, passing partial data from APIs, or spreading incomplete defaults. Here is the complete 2026 fix guide.
Why TS2739 happens
TypeScript checks that an object literal or expression provides every required property of the target type. Missing even one triggers TS2739 with the exact list. Fix by adding the missing property, making it optional in the target type, or spreading a default object first.
Fix 1: add the missing property
type Config = {
host: string;
port: number;
timeout: number;
};
// WRONG: missing timeout
const c: Config = { host: "localhost", port: 3000 };
// TS2739: Type '{ host: string; port: number; }' is missing the following properties from type 'Config': timeout
// FIX: provide the missing property
const c: Config = { host: "localhost", port: 3000, timeout: 5000 };Fix 2: spread a defaults object
type Config = {
host: string;
port: number;
timeout: number;
retries: number;
};
const DEFAULTS: Config = {
host: "localhost",
port: 3000,
timeout: 5000,
retries: 3,
};
// Now callers can pass overrides only
function build(overrides: Partial<Config>): Config {
return { ...DEFAULTS, ...overrides };
}
const c = build({ port: 8080 }); // fills the rest from DEFAULTSFix 3: make properties optional
// If the caller reasonably should NOT provide these, mark them optional
type Config = {
host: string;
port: number;
timeout?: number; // now optional
retries?: number;
};
const c: Config = { host: "localhost", port: 3000 }; // works
// But now downstream code must handle undefined
function connect(cfg: Config) {
const timeout = cfg.timeout ?? 5000;
const retries = cfg.retries ?? 3;
// ...
}Fix 4: React component props
type CardProps = {
title: string;
subtitle: string;
imageUrl: string;
onSelect: () => void;
};
// WRONG: missing onSelect
<Card title="Hi" subtitle="Sub" imageUrl="/img.png" />
// TS2739: missing 'onSelect'
// FIX 1: provide the missing prop
<Card title="Hi" subtitle="Sub" imageUrl="/img.png" onSelect={() => {}} />
// FIX 2: make it optional with default handler inside Card
type CardProps = {
title: string;
subtitle: string;
imageUrl: string;
onSelect?: () => void;
};
function Card(p: CardProps) {
const handleSelect = p.onSelect ?? (() => {});
return <div onClick={handleSelect}>...</div>;
}Debugging checklist
- Read the list of missing property names. TS2739 spells out every one.
- Decide whether the missing properties are truly required or should be optional.
- If often defaulted, put defaults in a DEFAULTS constant and spread them.
- If truly required, add them at the call site. Missing them is a real bug.
Real-world example: API DTO construction
type CreateUserDto = {
email: string;
password: string;
role: "admin" | "member";
verified: boolean;
createdAt: Date;
};
const DEFAULTS: Pick<CreateUserDto, "role" | "verified" | "createdAt"> = {
role: "member",
verified: false,
createdAt: new Date(),
};
function makeUserDto(email: string, password: string): CreateUserDto {
return { email, password, ...DEFAULTS };
}
const dto = makeUserDto("[email protected]", "s3cr3t");
// dto has all 5 required propertiesCommon mistakes when fixing TS2739
- Marking everything as optional to silence errors. Pushes the null check to every consumer.
- Using
asto cast an incomplete object. Downstream code will crash when it accesses missing properties. - Using
@ts-ignore. Removes the type check but keeps the bug. - Not using
Partialfor override parameters. Forces callers to provide every property.
Debugging TypeScript errors systematically
TypeScript errors follow a predictable pattern once you understand the compiler’s logic. Before jumping to fixes, run through this diagnostic checklist.
- Read the FULL error message. The compiler tells you both the actual type it sees and the expected type. Match them side by side to spot the mismatch.
- Check strictNullChecks and strict mode. Many errors trace back to
strict: truein tsconfig.json. If you inherited a codebase with strict mode on, expect more errors than in loose mode. - Look at inferred types with hover. VS Code shows inferred types on hover. Compare what TypeScript sees vs what you assumed.
- Use // @ts-expect-error strategically. When you know better than the compiler temporarily, mark the line. TypeScript flags the annotation when the underlying issue is fixed.
- Isolate the failing line in a minimal reproducer. A standalone
.tsfile with hardcoded inputs often surfaces the root cause faster than debugging in place.
Common TypeScript configuration issues
Many “why does this not compile” issues trace back to tsconfig.json, not your code.
- strict flag toggles many checks at once.
strict: trueenables strictNullChecks, noImplicitAny, strictFunctionTypes, and more. Turning on strict without preparing your code produces hundreds of errors. - Version mismatch between global and project TypeScript. Different TypeScript versions produce different errors. Pin the version in package.json for consistency.
- skipLibCheck can hide real issues. Setting
skipLibCheck: truespeeds up compilation but hides type mismatches in dependencies. Fine for CI but keep it off during development. - Path aliases and moduleResolution mismatches. The
pathsconfig in tsconfig only works with the right moduleResolution setting. Match “bundler” for Vite, “node16” for Node. - Ambient declarations vs modules. Files with imports are modules; files without imports are ambient scripts. Some errors happen because a file is treated as one when you expected the other.
Production TypeScript best practices
Once you get past errors and ship code, keep these habits to prevent recurring problems.
- Enable strict mode from day 1 on new projects. Migrating to strict later is 10x more work.
- Never use
anywithout a good reason.unknownis safer and forces you to narrow before use. - Avoid type assertions (
as) except at API boundaries. Assertions bypass the type system. Use them sparingly at edges (JSON parsing, DOM, external APIs). - Prefer type over interface for new code. Type aliases work everywhere interfaces do, plus support unions, intersections, and mapped types.
- Test type-level logic. Tools like
expect-typeortsdlet you write tests for your type definitions.
Learning resources for TypeScript
Beyond fixing the current error, deeper TypeScript knowledge pays dividends for years. Recommended starting points:
- Official Handbook. typescriptlang.org/docs/handbook. The canonical reference, well-written and up-to-date.
- Total TypeScript by Matt Pocock. Free tutorials and paid courses. Best for going from junior to advanced TypeScript.
- Type Challenges GitHub repo. Interactive problems that build type-level programming skills.
- TypeScript Deep Dive. Free online book, especially good for the “why” behind features.
- Try in the playground. typescriptlang.org/play lets you experiment with types and see errors immediately.
Official documentation
Frequently Asked Questions
TS2739 vs TS2345 difference?
TS2739 is specifically the “missing properties” flavor of TS2345 for object types. TypeScript emits TS2739 when it can name the missing properties explicitly, otherwise it falls back to TS2345.
Should missing properties always be optional?
No. If a property is truly required for the domain (an email in a User object), keep it required. Making everything optional creates a downstream null-check burden.
Is spreading defaults type-safe?
Yes when the DEFAULTS constant is typed as Pick<T, "keyA" | "keyB"> or a full T. Untyped spread can hide bugs.
Can I use Required to force all properties?
Yes. Required<T> strips ? from every property. Useful when converting a Partial input into a fully-populated internal state.
Does TS2739 apply to arrays?
Not by that name. Missing array elements or tuple positions surface as TS2322 or TS2345. TS2739 is specifically about object properties.
