Software Engineer | 45 questions | 2026
TypeScript Interview Questions and Answers
TypeScript interview questions for freshers 18
Q1FresherMost askedAnswerHideWhat is TypeScript, and why would you use it instead of plain JavaScript?
TypeScript is JavaScript with added types. It compiles to plain JavaScript. Every valid JS file is valid TS, and the type checker runs at build time only.
Why teams use it:
- Bugs such as typos in property names, wrong argument types and missing null checks are caught before the code runs.
- Editors give accurate autocomplete, go-to-definition and safe rename across the whole project.
- Types act as living documentation for function signatures and API shapes.
- Large refactors are safer because the compiler lists every place that breaks.
function total(price: number, qty: number): number {
return price * qty;
}
// @ts-expect-error: a string is not a number
total("10", 2);
Types are erased in the output, so they add no runtime cost and no runtime validation either. The trade-off is extra setup and a learning curve.
What they are checking: Whether you understand that TypeScript is a compile-time tool and can name concrete benefits
Q2FresherMost askedAnswerHideWhat is the difference between type and interface in TypeScript?
Both describe the shape of data, and for plain object shapes they are almost interchangeable. The practical differences:
interface | type | |
|---|---|---|
| Object shapes | Yes | Yes |
| Unions, tuples, primitives, mapped/conditional types | No | Yes |
| Extending | extends | Intersection & |
| Declaration merging | Yes (same name merges) | No (duplicate name is an error) |
implements in a class | Yes | Yes, if it is an object type |
interface User { id: number; name: string }
interface Admin extends User { role: "admin" }
type Id = string | number; // only a type alias can do this
type Point = [number, number];
A common convention: use interface for public object shapes and class contracts (it can merge and gives clearer error messages). Use type for unions, tuples and computed types. Pick one rule per codebase and stay consistent.
What they are checking: Whether you know the real differences (merging, unions) and not just 'they are the same'
Q3FresherMost askedAnswerHideWhat is the difference between any, unknown and never?
anyturns off type checking for a value. You can do anything with it and the compiler stays silent. It spreads unsafety.unknownis the type-safe version of any. Anything can be assigned to it, but you must narrow it before using it.neveris the type with no values. It is the return type of functions that never return (they throw or loop forever). It is also the type left over after every case has been narrowed out.
let a: any = "hi";
a.toFixed(); // compiles, crashes at runtime
let u: unknown = "hi";
// @ts-expect-error: must narrow first
u.toUpperCase();
if (typeof u === "string") u.toUpperCase(); // ok
function fail(msg: string): never {
throw new Error(msg);
}
Prefer unknown for data you do not control (JSON, catch clauses, third-party input). Avoid any unless nothing else works.
What they are checking: Whether you reach for unknown instead of any and understand never as the empty type
Q4FresherMost askedAnswerHideWhat are generics in TypeScript and why are they useful?
Generics let you write a function, class or type that works with many types. They keep the link between the input type and the output type. Think of a type parameter as a variable for a type.
function first<T>(items: T[]): T | undefined {
return items[0];
}
const n = first([1, 2, 3]); // number | undefined
const s = first(["a", "b"]); // string | undefined
interface ApiResponse<TData> {
data: TData;
status: number;
}
const res: ApiResponse<{ id: number }> = { data: { id: 1 }, status: 200 };
Without generics you would either duplicate the function per type or return any and lose safety. Typical uses are collections, API response wrappers, React hooks and utility types. TypeScript usually works out T from the arguments, so callers rarely write it.
What they are checking: Whether you can explain generics as type variables that preserve type relationships
Q5FresherMost askedAnswerHideExplain the common utility types Partial, Pick, Omit, Required and Record with examples.
Utility types are built-in generic types that transform other types.
interface User { id: number; name: string; email: string }
type Draft = Partial<User>; // all optional
type Full = Required<Draft>; // all required again
type Preview = Pick<User, "id" | "name">; // only these keys
type NoEmail = Omit<User, "email">; // everything except
type Roles = Record<"admin" | "user", string[]>; // fixed keys to value type
const patch: Partial<User> = { name: "Asha" }; // update payload
const roles: Roles = { admin: ["a"], user: [] };
Partial<T>: update/patch payloads, form drafts.Pick<T, K>andOmit<T, K>: derive smaller shapes without repeating fields (for example removing a password before sending a user to the client).Record<K, V>: dictionaries and lookup tables with known keys.Readonly<T>: makes all properties read-only.
They are plain mapped types under the hood, so you can write your own the same way.
What they are checking: Whether you reach for utility types instead of copy-pasting interfaces
Q6FresherMost askedAnswerHideWhat is type narrowing, and what are type guards?
Narrowing is when TypeScript changes a broad type to a more specific one inside a code branch, after a check. A type guard is the check (or function) that triggers it.
Built-in narrowing: typeof, instanceof, in, equality, truthiness.
function show(x: string | number | Date) {
if (typeof x === "string") return x.toUpperCase();
if (x instanceof Date) return x.toISOString();
return x.toFixed(2); // number
}
interface Cat { meow(): void }
interface Dog { bark(): void }
function isCat(a: Cat | Dog): a is Cat { // user-defined guard
return "meow" in a;
}
function talk(a: Cat | Dog) {
if (isCat(a)) a.meow(); else a.bark();
}
A function returning a is Cat is a type predicate: when it returns true, the argument is treated as Cat in that branch. Assertion functions (asserts x is T) narrow after the call by throwing on failure. Be honest in predicates: the compiler trusts you.
What they are checking: Whether you can narrow safely and write a custom type predicate
Q7FresherMost askedAnswerHideWhat does strict mode in tsconfig.json turn on, and why should it be enabled?
"strict": true enables a group of checks. The important ones:
strictNullChecks:nullandundefinedcannot be assigned to other types. This stops most "cannot read property of undefined" bugs.noImplicitAny: variables and parameters with no inferable type are errors instead of silentlyany.strictFunctionTypes,strictBindCallApply,strictPropertyInitialization,noImplicitThis,useUnknownInCatchVariables,alwaysStrict.
{
"compilerOptions": {
"target": "ES2022",
"module": "esnext",
"moduleResolution": "bundler",
"strict": true,
"noUncheckedIndexedAccess": true,
"skipLibCheck": true
}
}
Without strict, much of TypeScript's value is lost. Gaps remain, like hidden any and values that can be null anywhere. New projects should start strict. noUncheckedIndexedAccess is not part of strict but is worth adding because array and record lookups become T | undefined.
What they are checking: Whether you know strict is a family of flags and can name the key ones
Q8FresherMost askedAnswerHideHow do you type props for a React component in TypeScript?
Declare an interface or type for the props and annotate the destructured parameter. Typing the function directly is preferred over React.FC in modern code.
import type { ReactNode } from "react";
interface ButtonProps {
label: string;
variant?: "primary" | "ghost";
disabled?: boolean;
onClick: (id: number) => void;
children?: ReactNode;
}
export function Button({ label, variant = "primary", disabled, onClick, children }: ButtonProps) {
return (
<button className={variant} disabled={disabled} onClick={() => onClick(1)}>
{label}
{children}
</button>
);
}
- Use
?for optional props and default values in destructuring. - Use
ReactNodefor anything renderable (children), andReactElementonly when an element is required. - Extend native element props with
React.ComponentProps<"button">orComponentPropsWithoutRef<"button">so your component acceptstype,aria-*and so on. - Type callbacks precisely instead of
Function.
What they are checking: Whether you can type props, optional props, children and callbacks cleanly
Q9FresherMost askedFree with sign-inAnswerHideWhat is the difference between union and intersection types?
A union (A | B) means a value is either A or B. An intersection (A & B) means a value is both A and B at once.
Q10FresherMost askedFree with sign-inAnswerHideEnums versus union literal types: which would you choose and why?
In most modern code I prefer string literal unions. I use enums only when I need a runtime object or must match existing code.
Q11FresherMost askedFree with sign-inAnswerHideWhat do keyof and typeof do in TypeScript?
Both are used in type positions to build types from existing things.
keyof Tproduces a union of the property names of type T.typeof value(in a type position) gets the type of a variable or object value. It is different from the runtimetypeofoperator that returns a string.
Q12FresherMost askedFree with sign-inAnswerHideWhat is the difference between a type annotation, a type assertion (as) and the non-null assertion (!)?
- Annotation (
x: T): you declare the type, and the compiler checks the value matches. - Assertion (
x as T): you tell the compiler to treat a value as T. No runtime check or conversion happens. It only works when the types overlap enough. Otherwise you needas unknown as T. - Non-null assertion (
x!): tells the compiler the value is not null or undefined.
Q13FresherMost askedFree with sign-inAnswerHideWhat is type inference, and when should you write the types yourself?
Type inference is TypeScript working out types from values and usage, so you do not write them everywhere.
Q14FresherMost askedFree with sign-inAnswerHideWhat is a declaration file (.d.ts), and what is DefinitelyTyped (@types)?
A .d.ts file contains only type declarations, no implementation. It describes the shape of JavaScript code so TypeScript can type-check calls to it.
Q15FresherMost askedFree with sign-inAnswerHideWhat does readonly do, and how does it differ from const?
const stops you from assigning a new value to a variable. readonly stops you from assigning a new value to a property (or array elements) through that type. Neither makes an object deeply immutable at runtime.
Q16FresherMost askedFree with sign-inAnswerHideWhat are tuples in TypeScript, and when would you use one?
A tuple is an array with a fixed length where each position has its own type.
Q17FresherMost askedFree with sign-inAnswerHideWhat is the difference between void, undefined and null as return types?
undefinedis a value and a type: the variable exists but has no value.nullis a "no value" that you assign on purpose.voidis the return type of a function whose result you are not supposed to use. Such a function returnsundefinedat runtime.
Q18FresherFree with sign-inAnswerHideWhat is the difference between object, {} and Object as types in TypeScript?
objectmeans any non-primitive value (objects, arrays, functions), but notstring,number,boolean,nullorundefined. Use it when you want "some object" and will narrow later.{}means any value that is notnullorundefined, so it accepts primitives like5and"a"too. It almost never means what people expect.Objectis the type of the globalObjectinterface, which also includes primitives that are boxed. It should be avoided.
TypeScript interview questions for experienced 16
Q19ExperiencedMost askedFree with sign-inAnswerHideHow do generic constraints and default type parameters work?
A constraint with extends limits what a type parameter may be, so you can safely use its members. A default gives the parameter a fallback when it cannot be inferred or is not supplied.
Q20ExperiencedMost askedFree with sign-inAnswerHideWhat do ReturnType, Parameters and Awaited do, and when would you use them?
They extract types from existing functions or promises, so you do not repeat or drift from the source.
Q21ExperiencedMost askedFree with sign-inAnswerHideWhat is a discriminated union, and why is it useful?
A discriminated union is a union of object types that share a literal-typed property (the discriminant). Checking that property lets TypeScript narrow to exactly one member.
Q22ExperiencedMost askedFree with sign-inAnswerHideWhat are mapped types? Write one.
A mapped type builds a new type by looping over the keys of another type with [K in keyof T]. It can also change modifiers or value types. Most utility types are mapped types.
Q23ExperiencedMost askedFree with sign-inAnswerHideHow do you type useState, event handlers and refs in React with TypeScript?
Let inference work where it can, and add a generic where the initial value does not tell the full type.
Q24ExperiencedMost askedFree with sign-inAnswerHideHow do you do exhaustive checking with never, and why does it matter?
Assign the leftover value to never in the default branch. If every union member is handled, the leftover type is never and it compiles. If someone adds a new member later, the assignment fails and the compiler points to the switch that needs updating.
Q25ExperiencedMost askedFree with sign-inAnswerHideWhat are conditional types and the infer keyword?
A conditional type picks one of two types based on a check: T extends U ? X : Y. With infer you can capture a part of the matched type into a new type variable.
Q26ExperiencedMost askedFree with sign-inAnswerHideWhat do 'as const' and the 'satisfies' operator do?
as const makes a value deeply readonly and keeps literal types instead of widening them. satisfies checks that a value matches a type without changing the inferred type of the value.
Q27ExperiencedMost askedFree with sign-inAnswerHideWhat are function overloads in TypeScript? When are generics a better option?
Overloads declare several call signatures for one function, followed by a single implementation that handles all of them. Callers see only the overload signatures.
Q28ExperiencedMost askedFree with sign-inAnswerHideIs TypeScript structurally or nominally typed? What are branded types?
TypeScript is structurally typed: two types are compatible if their shapes match, regardless of names. That means a UserId and an OrderId that are both number are interchangeable, which can hide bugs.
Q29ExperiencedMost askedFree with sign-inAnswerHideWhat are index signatures, how do they differ from Record, and what does noUncheckedIndexedAccess do?
An index signature says an object can have any number of keys of a given type: { [key: string]: number }. Record<K, V> is a mapped type that expresses the same idea and also works with a union of known keys.
Q30ExperiencedMost askedFree with sign-inAnswerHideInterface extends versus intersection types: how do they differ when properties conflict?
Both combine shapes, but they report conflicts differently.
Q31ExperiencedMost askedFree with sign-inAnswerHideHow do you write a generic React component, such as a reusable list or select that works with any item type?
Make the function component generic. The props use the type parameter, and TypeScript infers it from what the caller passes.
Q32ExperiencedMost askedFree with sign-inAnswerHideWhat is declaration merging and module augmentation? Show how to add a property to an existing type such as Express Request.
Declaration merging means TypeScript joins several declarations with the same name into one. Interfaces merge, and namespaces merge with classes and functions. Module augmentation applies that to a third-party module: you reopen its declarations and add to them.
Q33ExperiencedFree with sign-inAnswerHideWhat are template literal types? Give a practical example.
Template literal types build string literal types using the same backtick syntax as JavaScript templates, and they distribute over unions.
Q34ExperiencedFree with sign-inAnswerHideWhat do covariance and contravariance mean for function parameters, and what does strictFunctionTypes change?
Covariance means a more specific type can be used where a general one is expected (return types). Contravariance is the reverse: a function that accepts a general type can stand in for one that accepts a specific type (parameters).
Scenario based TypeScript interview questions 11
Q35ExperiencedMost askedScenarioAnswerHideTypeScript types are erased at runtime. How do you validate data coming from an API or form safely?
Types do not exist at runtime, so a fetch().json() result typed as User is just a guess. Check the data where it enters your app, using a runtime schema library (Zod, Valibot, ArkType). Get the static type from the schema, so the two never get out of sync.
import { z } from "zod";
const UserSchema = z.object({
id: z.number(),
name: z.string().min(1),
email: z.string().email().optional(),
});
type User = z.infer<typeof UserSchema>;
async function getUser(id: number): Promise<User> {
const res = await fetch(`/api/users/${id}`);
if (!res.ok) throw new Error(`HTTP ${res.status}`);
const json: unknown = await res.json();
return UserSchema.parse(json); // throws a clear error if the shape is wrong
}
Practical points:
- Treat all external input (network, localStorage, query string, env vars) as
unknownuntil parsed. - Use
safeParsewhere you want to handle errors without exceptions. - Share the schema between client and server so both validate the same contract.
- Hand-written type guards work for tiny shapes but get long fast.
What they are checking: Whether you understand the limit of static types and validate untrusted data at the edge
Q36ExperiencedMost askedScenarioAnswerHideAn API returns JSON and the team wants the response typed. How would you handle it?
I would never trust the type for data from outside the program. The flow:
- Define the expected shape once as a runtime schema (Zod or similar) and infer the TypeScript type from it.
- Keep the raw result as
unknownand parse it in one wrapper function so nobody reads unvalidated data. - Handle failure on purpose (bad status, bad shape). Return a result type or throw a typed error.
import { z } from "zod";
const Todo = z.object({ id: z.number(), title: z.string(), done: z.boolean() });
type Todo = z.infer<typeof Todo>;
async function fetchJson<T>(url: string, schema: z.ZodType<T>): Promise<T> {
const res = await fetch(url);
if (!res.ok) throw new Error(`Request failed: ${res.status}`);
const body: unknown = await res.json();
return schema.parse(body);
}
const todos = await fetchJson("/api/todos", z.array(Todo));
If the backend is also TypeScript, share the schema package or generate types from an OpenAPI/GraphQL spec. Then a contract change breaks the build instead of production. A bare as Todo[] cast is acceptable only for trusted internal data and should be a conscious exception.
What they are checking: Whether you validate at the boundary and keep a single source of truth for the contract
Q37FresherMost askedScenarioFree with sign-inAnswerHideYou get the error "Property 'x' does not exist on type 'A | B'". What causes it and how do you fix it?
When a value has a union type, you can only access properties that exist on every member. TypeScript does not know yet which member you have. So using a property that exists on only one of them is an error.
Q38ExperiencedMost askedScenarioFree with sign-inAnswerHideYou have a large JavaScript codebase. How would you migrate it to TypeScript incrementally?
Migrate gradually so the app keeps shipping.
Q39ExperiencedMost askedScenarioFree with sign-inAnswerHideHow would you build a type-safe API client where each endpoint has its own request and response types?
Describe all endpoints in one map type, then make a generic function that looks up the types by path. The compiler then knows the body and the result for each call.
Q40ExperiencedMost askedScenarioFree with sign-inAnswerHideHow would you model loading, success and error states for a data fetch in a React component?
Use a discriminated union instead of separate boolean flags, so impossible combinations (loading and error at once) cannot exist.
Q41ExperiencedMost askedScenarioFree with sign-inAnswerHideA function should accept either a single item or an array of items and return the same shape. How would you type it?
Use a generic with a conditional return type, or overloads, so the output depends on the input.
Q42ExperiencedMost askedScenarioFree with sign-inAnswerHideThe TypeScript build (tsc) has become very slow in a large monorepo. What would you do?
First measure, then reduce the work.
Q43ExperiencedMost askedScenarioFree with sign-inAnswerHideA third-party library returns any in several places. How do you keep your codebase type-safe?
Contain the unsafety at the boundary so any never leaks into the rest of the code.
Q44ExperiencedMost askedScenarioFree with sign-inAnswerHideHow would you configure tsconfig.json for a Next.js or other modern bundled app, and what do the key options mean?
The bundler does the emitting, so TypeScript is used only for checking.
Q45ExperiencedMost askedScenarioFree with sign-inAnswerHideYour team resists turning on strict mode because the codebase has thousands of errors. How do you roll it out?
Enable it gradually and stop the debt from growing.