FAQ Portal
Categories
Search
About
Contacts
UK
RU
EN
Home
Technology
Programming
TypeScript
TypeScript
100 questions
How to install TypeScript in a project?
•
npm i -D typescript.
•
npx tsc --init will create tsconfig.json.
•
Add scripts: tsc, tsc -w.
•
For Node: npm i -D ts-node.
•
Check: npx tsc -v.
What is tsconfig.json and what does it control?
•
It is the compiler configuration.
•
target/module define the output JS.
•
strict enables strict checks.
•
include/exclude manage files.
•
paths/baseUrl configure aliases.
How do type and interface differ?
•
interface extends via extends.
•
interface supports declaration merging.
•
type is convenient for union/intersection.
•
For objects, interface is more common, but not a rule.
•
In practice, choose based on task and team style.
What is strict mode in TypeScript and why should you enable it?
•
strict enables a set of strict flags.
•
Catches errors with null/undefined and types.
•
Improves autocompletion and refactoring.
•
Enhances code quality in large projects.
•
Enable gradually if the project is old.
What is any and why should you avoid it?
•
any disables type checking.
•
Errors move to runtime.
•
Instead of any, use unknown, generics, or precise types.
•
For migration, you can temporarily use any but plan to remove it.
•
You can restrict via eslint/tsconfig.
How does unknown differ from any?
•
unknown is safer: cannot use without checking.
•
Requires narrowing (typeof, in, instanceof).
•
Suitable for external data (JSON).
•
any is a 'hole' in types.
•
With unknown, errors are caught at compile time.
How to type the result of JSON.parse?
•
JSON.parse returns any.
•
Use unknown and validate structure.
•
Create a type guard or schema (zod).
•
After validation, cast to the desired type.
•
Do not blindly use as YourType without checking.
What is type narrowing and how does it work?
•
It is narrowing the type in code branches.
•
Use typeof for primitives.
•
Use in/instanceof for objects/classes.
•
Custom type guards also narrow the type.
•
Helps write code without unnecessary casts.
How to write a type guard function?
•
The function returns an expression of the form x is T.
•
Inside, check fields and types.
•
Use for unknown/union.
•
Keep checks simple and cover with tests.
•
Schema validation (zod) is often more reliable.
What are union types and where are they useful?
•
Union: A | B.
•
Good for limited sets of values.
•
Often used with a discriminant field.
•
Requires narrowing before accessing specific fields.
•
Improves API expressiveness.
What are intersection types and when to use them?
•
Intersection: A & B.
•
Combines properties of multiple types.
•
Convenient for compositions and mixins.
•
Be careful with conflicting fields.
•
Commonly found in library types.
What are literal types and why are they needed?
•
Literal types: 'GET', 200, true.
•
Basis for union of specific values.
•
Useful for statuses, roles, modes.
•
Work with as const.
•
Help avoid typos.
Why is as const needed?
•
Makes literals immutable and narrow.
•
Turns array into readonly tuple.
•
Useful for configs and dictionaries.
•
Simplifies type inference.
•
Often used with satisfies.
What is satisfies and how is it better than 'as'?
•
satisfies checks conformity to a type but preserves inference.
•
Doesn't 'narrow' values like as.
•
Useful for configs and mappings.
•
Helps catch key/field errors.
•
Available in TS 4.9+.
How to type an object dictionary with fixed keys?
•
Use Record<K, V>.
•
K can be union literals.
•
For partial keys — Partial<Record<...>>.
•
For validation without losing inference — satisfies.
•
For dynamic keys — index signature.
What is an index signature and when is it needed?
•
{[key: string]: Value}.
•
For objects with unknown keys.
•
Limits the type of all values.
•
Can conflict with specific fields — be careful.
•
Sometimes better to use Map<string, V>.
How to type an array with a fixed structure (tuple)?
•
Tuple: [number, string].
•
Can make readonly tuple via as const.
•
For named elements: [id: string, value: number].
•
Convenient for key-value pairs.
•
For larger structures, better to use interface.
What are generics and why are they needed?
•
Allow parameterizing types.
•
For example: function first<T>(a: T[]): T.
•
Remove code duplication.
•
Can constrain T via extends.
•
Improve library typing.
How to constrain generics using extends?
•
<T extends { id: string }>.
•
Then T is guaranteed to have an id.
•
You can constrain with a union.
•
Use extends keyof for keys.
•
Constraints improve autocomplete.
How to type the function getProperty(obj, key)?
•
<T, K extends keyof T>(obj: T, key: K) => T[K].
•
keyof gives a set of keys.
•
T[K] returns the type of the value at the key.
•
Works with optional fields too.
•
This is a canonical example of generics.
What is keyof and why is it useful?
•
keyof T gives a union of the keys of type T.
•
Allows safe indexing.
•
Useful in utility types like Pick/Omit.
•
Helps build type-safe APIs.
•
Works with mapped types.
What are mapped types?
•
Types like { [K in keyof T]: ... }.
•
Allow transforming fields.
•
They underpin Partial/Required/Readonly.
•
You can change modifiers: -? / +readonly.
•
Powerful tool for libraries.
How does Partial<T> work and when to use it?
•
Makes all fields optional.
•
Convenient for patch objects (update).
•
Danger: guarantees of field presence are lost.
•
Often better to use Partial<Pick<T, ...>>.
•
Good for input forms.
What is the difference between Pick and Omit?
•
Pick takes a subset of fields.
•
Omit excludes fields.
•
Useful for DTOs and public models.
•
Avoid duplicating structures.
•
Combine with Partial/Required.
What is Record<K, V> and where is it useful?
•
Record creates an object with keys K and values V.
•
Useful for dictionaries and mappings.
•
K can be a union.
•
For incomplete keys, use Partial<Record<...>>.
•
For strict key checking — satisfies.
How to type callback functions?
•
Describe the signature: type Fn = (x: number) => string.
•
For events — use library types (React, DOM).
•
For async — Promise<...>.
•
Don't forget optional parameters.
•
Make the return type explicit.
How to type Promise and async/await?
•
async function returns Promise<T>.
•
Specify the result type: Promise<User>.
•
await unwraps the Promise.
•
Handle errors with try/catch.
•
Don't return any from async chains.
What are overloads of functions?
•
You can declare multiple signatures.
•
Implementation is one, but types differ.
•
Useful for functions with different modes.
•
Overloads should be compatible.
•
Sometimes easier to use union and narrowing.
What is the difference between type assertion (as) and actual type checking?
•
as does not check at runtime.
•
It tells the compiler: 'trust me'.
•
Can hide bugs.
•
It's better to validate data first.
•
Use as only when you are sure of the structure.
What is non-null assertion (!) and why is it dangerous?
•
x! indicates that x is not null/undefined.
•
The compiler stops warning.
•
It can fail at runtime if you are wrong.
•
Better to check with if (x) or optional chaining.
•
Use sparingly and consciously.
How does optional chaining (?.) work?
•
Allows safe access to nested fields.
•
obj?.a?.b returns undefined if something is missing.
•
Works with function calls: fn?.().
•
Does not replace business validation.
•
Convenient for UI and API data.
How does nullish coalescing (??) work?
•
a ?? b takes b only if a is null/undefined.
•
Not confused with 0/''/false like ||.
•
Great for defaults.
•
Often combined with optional chaining.
•
Understand the difference between || and ??.
How to type errors in catch in strict mode?
•
In TS, catch variable is often unknown.
•
Check: err instanceof Error.
•
Log safely: String(err).
•
For libraries, create your own error types.
•
Do not assume structure without checking.
What is discriminated union and how to design it?
•
Union with a tag field: type: 'a' | 'b'.
•
In switch on the tag, the type narrows automatically.
•
Useful for events and state.
•
Add exhaustive check (never).
•
One of the best patterns in TS.
How to do exhaustive check in switch?
•
Assign a variable of type never in default.
•
If a new union variant appears — the compiler will warn.
•
Example: const _exhaustive: never = x.
•
Helps maintain code.
•
Especially useful in reducers.
How to type classes and their fields in TypeScript?
•
Specify modifiers: public/private/protected.
•
Declare fields in advance or in constructor.
•
Use readonly for immutable fields.
•
Parameter properties: constructor(private api: Api) {}.
•
Do not overuse classes if functions suffice.
What is abstract class and interface: which to choose?
•
interface describes a contract without implementation.
•
abstract class can contain common implementation.
•
In TS, you can implement multiple interfaces but inherit from one class.
•
For 'ports' and APIs, usually enough to use interface.
•
Abstract is convenient for base components/templates.
How to type this in methods and functions?
•
In class methods, this is inferred automatically.
•
For functions, specify this parameter: function f(this: X) {}.
•
Arrow functions take this from external context.
•
In callbacks, this is often lost — bind or use arrows.
•
Proper typing catches errors.
How does enum work and why is union often recommended instead of enum?
•
enum generates runtime code (usually).
•
Can complicate the bundle.
•
Literal unions are simpler and tree-shakable.
•
If a runtime value is needed — you can use enum or const object.
•
const enum speeds up, but is risky for libraries.
What is a const enum and what are its risks?
•
const enum is inlined into the code.
•
Reduces runtime overhead.
•
Can break when building libraries and with different configurations.
•
Not always compatible with babel/transpileOnly.
•
Often better to use object + as const.
How to type higher-order functions (HOF)?
•
Generalize input and output types.
•
Keep the signature via generics.
•
For function decorators, use <T extends (...a: any[]) => any>.
•
Return Parameters<T> and ReturnType<T>.
•
This provides strong typing.
What are ReturnType and Parameters and when are they needed?
•
ReturnType<F> takes the function's result type.
•
Parameters<F> takes the tuple of arguments.
•
Useful for wrappers and proxies.
•
Reduces duplication.
•
Works only with function types.
How to type a safe event emitter system?
•
Create a map: EventName -> payload type.
•
on<K extends keyof Events>(name: K, cb: (p: Events[K]) => void).
•
emit similarly.
•
This way, you avoid type errors in events.
•
A good pattern for frontend and Node.
How to type an API client and server responses?
•
Define DTO types for responses.
•
Use runtime validation for external data.
•
For fetch, create a request<T>() function returning Promise<T>.
•
Never trust the server without checks.
•
Log and handle status errors.
How to type fetch and JSON processing?
•
const res = await fetch(url).
•
Check res.ok.
•
const data: unknown = await res.json().
•
Validate data and then cast to type.
•
Add timeouts/retries separately.
How to properly work with DOM types in TS?
•
Enable lib: ['DOM'].
•
Use querySelector with generics: document.querySelector<HTMLDivElement>('...').
•
Check for null.
•
For events, use MouseEvent/KeyboardEvent.
•
Don't cast without necessity.
How to type addEventListener and handlers?
•
element.addEventListener('click', (e) => { ... }).
•
e has type MouseEvent (for click).
•
Types for window/document are also available.
•
If needed, specify target via instanceof.
•
Don't use any for events.
How to type React components in TypeScript?
•
Props via interface/type.
•
function Component(props: Props) { ... }.
•
For children: React.ReactNode.
•
For events: React.ChangeEvent<HTMLInputElement>.
•
React.FC is not always necessary.
When to use React.FC and when not to?
•
React.FC adds children by default.
•
Sometimes this is undesirable.
•
DefaultProps typing differs.
•
Simple functions with Props are usually enough.
•
Choose a consistent style in the project.
How to type useState in React?
•
useState<number>(
•
fixes the type.
•
For nullable: useState<User | null>(null).
•
For complex objects, an interface is better.
•
Lazy initialization: useState(() => compute()).
•
Avoid any in state.
How to type useRef?
•
useRef<HTMLDivElement | null>(null).
•
Check ref.current for null.
•
For mutable value: useRef<number>(0).
•
Do not use ref as state.
•
For callbacks, you can use useCallback ref.
What is declaration merging and where does it occur?
•
An interface can merge by name.
•
Convenient for extending global types.
•
Often used to augment Window/NodeJS.ProcessEnv.
•
Can be a source of conflicts.
•
Control where you declare global types.
How to extend the type Window or ProcessEnv?
•
Create a d.ts file in the project.
•
declare global { interface Window { ... } }.
•
For env: declare namespace NodeJS { interface ProcessEnv { ... } }.
•
Don't forget export {} in the file.
•
Make sure include sees this file.
What are .d.ts files and why are they needed?
•
These are type declaration files.
•
Needed for JS libraries without types.
•
Can describe API without implementation.
•
Used by DefinitelyTyped (@types/*).
•
Included via types/include.
How to add types for a JS library without @types?
•
First check if there are built-in types.
•
If not — create a minimal .d.ts with declare module 'lib'.
•
Gradually refine types as you use them.
•
You can write a wrapper API with strict types.
•
For complex cases — generate from OpenAPI/JSON schema.
What is moduleResolution and when to change it?
•
Determines how TS searches for modules.
•
NodeNext is needed for ESM/Node 16+.
•
Bundler is suitable for Vite/webpack.
•
Classic is rarely needed.
•
Choice depends on runtime and bundler.
How to configure path aliases (paths) in tsconfig?
•
Set baseUrl.
•
Add paths: { '@/*': ['src/*'] }.
•
Configure the bundler (webpack/vite) similarly.
•
Configure jest/vitest aliases too.
•
Otherwise, aliases won't work at runtime.
Why does TS pass, but the module is not found at runtime?
•
TS checks paths via tsconfig paths.
•
But Node/bundler may not recognize aliases.
•
You need to configure resolver in bundler/tests.
•
For Node, you can use tsconfig-paths.
•
Always check runtime configuration.
What is isolatedModules and when is it needed?
•
Required for transpiling via Babel/'single file'.
•
Prohibits certain constructs (e.g., const enum).
•
Helps with compatibility with bundlers.
•
Usually enabled in Next.js.
•
Better to keep it enabled in frontend projects.
What is the difference between tsc and babel/swc when building TS?
•
tsc performs type checking and can emit JS.
•
Babel/SWC transpile quickly but do not check types.
•
In such schemes, type checks are run separately (tsc --noEmit).
•
Next/Vite often use SWC/Babel.
•
Type checking is needed in CI.
How to enable type checking without generating JS?
•
Run: tsc --noEmit.
•
Or set noEmit: true in tsconfig.
•
Convenient for projects where another tool handles the build.
•
In CI, do a separate step for typecheck.
•
Type errors then do not go into production.
What are source maps and how do they help?
•
Link compiled JS with the original TS.
•
Simplify debugging in browser and Node.
•
Enable with sourceMap: true.
•
Sometimes disabled in production due to size and security.
•
Useful for Sentry.
How to properly type config objects?
•
Use const + as const for literals.
•
Use satisfies to check structure.
•
Avoid any.
•
Keep config in one place, do not spread.
•
For env values, do explicit type conversion.
How to type process.env and remove 'string | undefined'?
•
Variables may be missing at runtime.
•
First validate presence (e.g., via requireEnv function).
•
After validation, can return string.
•
Better to have a single configuration layer.
•
For strict schema, use zod/valibot.
How to type a function that throws an error (never)?
•
Functions that always throw/terminate process return never.
•
Example: function fail(msg: string): never { throw new Error(msg) }.
•
Useful in exhaustive checks.
•
Helps flow analysis.
•
Improves error readability.
What are template literal types?
•
String types with a template: `user:${string}`.
•
Useful for building keys and routes.
•
Work with union and mapped types.
•
Complicate types, use carefully.
•
Great for events/ID tags.
How to type strings like UUID/id?
•
Full validation with types is not possible.
•
Can create a branded type: type UUID = string & { __brand: 'UUID' }.
•
Convert only after regex check.
•
Increases API safety.
•
Without runtime check, brand is meaningless.
What are branded types and why are they needed?
•
A way to distinguish identical primitives (string vs Email).
•
Done via intersection with a 'marker'.
•
Requires factory/validation.
•
Reduces errors when passing parameters.
•
Useful in domain modeling.
How to type validator functions?
•
Return boolean and type predicate.
•
For example: (x: unknown): x is User.
•
Keep checks at the same level, without side effects.
•
Schema validation is often simpler.
•
Add tests for validators.
What are conditional types?
•
Types like T extends U ? X : Y.
•
Used for smart utilities.
•
Can distribute over union.
•
Sometimes significantly slow down compilation.
•
Mainly use in library code.
What is infer in conditional types?
•
infer allows 'extracting' part of a type.
•
For example, to get the type of an array element.
•
Used in ReturnType/Parameters.
•
Powerful, but harder to read.
•
Write examples and test types.
How to get the type of an array element?
•
For array T[] element is T.
•
For arbitrary: type Elem<A> = A extends (infer T)[] ? T : never.
•
Consider readonly for readonly arrays.
•
Useful in generic utilities.
•
Don't forget about tuple.
What are utility types Required/Readonly and why?
•
Required makes fields mandatory.
•
Readonly makes fields read-only.
•
Use for public interfaces and immutability.
•
There is ReadonlyArray and readonly tuple.
•
Reduces mutations in code.
How to type a partial update of an object more safely?
•
Don't do Partial<T> on everything.
•
Limit the set of fields: Partial<Pick<T, 'a' | 'b'>>.
•
To forbid some fields — Omit.
•
Validate data before applying.
•
For API, better to use a separate DTO.
How to type a merge function without losing types?
•
<A extends object, B extends object>(a: A, b: B): A & B.
•
But consider conflicting keys.
•
At runtime, use Object.assign/spread.
•
For deep merge, types are more complex.
•
Sometimes explicit description of the result is better.
How to work with readonly and object mutations?
•
Readonly forbids assigning to fields.
•
For changes, create a copy via {...obj}.
•
For arrays: [...arr].
•
Use immutable patterns in state.
•
For deep structures, discipline/immer is needed.
How to type an object that can be null?
•
Use union: T | null.
•
Check with if (x == null) return.
•
Avoid ! for bypassing.
•
For chain access, use ?.
•
Think about where null is allowed.
How to properly choose between null and undefined?
•
undefined often means 'no value' by default.
•
null is often used as explicit 'empty'.
•
Keep a consistent style in the project.
•
Better to document in API.
•
Both require handling in strictNullChecks.
How to type functions with optional parameters?
•
Parameter: foo(x?: string).
•
Or foo(x: string | undefined).
•
Keep in mind that x can be undefined.
•
Set default: function foo(x: string = 'a').
•
Don't make many optionals in a row — better to use a parameter object.
How to type an 'options object' instead of a long list of arguments?
•
Create interface Options { ... }.
•
function f(opts: Options) {}.
•
Provide defaults via destructuring.
•
This is more convenient for API extension.
•
Allows using Partial<Options> for defaults.
How does structural typing work in TypeScript?
•
In TS, the structure matters, not the name of the type.
•
Two types are compatible if their fields match.
•
This is convenient but can hide domain errors.
•
Branded types help distinguish.
•
Always consider system boundaries.
What is nominal typing and how to emulate it in TS?
•
Nominal — compatibility by type name.
•
In TS, you can emulate via brands.
•
type UserId = string & { __brand: 'UserId' }.
•
Create a constructor function after validation.
•
This reduces accidental substitutions.
How to type functions working with arrays (map/filter/reduce) without any?
•
TS infers callback types automatically.
•
Ensure the source array is typed.
•
For reduce, specify initial value and accumulator type.
•
Avoid reduce without initial — issues may occur.
•
For filter, sometimes a type guard is needed.
How to make a type guard for filter?
•
Example: const isDefined = <T>(x: T | undefined): x is T => x !== undefined.
•
Then arr.filter(isDefined) removes undefined.
•
Similarly for null.
•
Useful in data pipelines.
•
Make such utilities in one place.
What is satisfies for arrays and dictionaries?
•
You can check array types without losing literal types.
•
Example: const routes = [...] satisfies Route[].
•
The compiler will check the structure of elements.
•
But will keep specific value types.
•
Good balance between 'as is' and strict checking.
How to speed up TypeScript compilation in a large project?
•
Enable incremental.
•
Use project references.
•
Reduce include and exclude build/output folders.
•
Avoid complex conditional types in hot spots.
•
Update TS to the latest version.
What are project references and why are they needed?
•
They split a monorepo into TS projects.
•
Speed up build and type checking.
•
Allow 'incremental' checking of only changed parts.
•
Require composite: true.
•
Good for large codebases.
How to set up a monorepo with TypeScript?
•
Use a workspace manager (pnpm/yarn/npm).
•
Create a base tsconfig and extend it.
•
Enable project references.
•
Keep TS and types versions consistent.
•
Configure linter and formatter uniformly.
How to properly type a public API of a library?
•
Export only the necessary types.
•
Do not export internal details.
•
Stabilize the contract and version it.
•
Generate d.ts (declaration: true).
•
Test types with dtslint or tsd.
How to check types in CI?
•
Add a script: npm run typecheck.
•
Run tsc --noEmit.
•
Run eslint/test separately.
•
Do not rely on IDE.
•
Make the check mandatory before merge.
How to type a Node.js project in TypeScript?
•
Configure module and moduleResolution for ESM/CJS.
•
Add @types/node.
•
Choose a runner: ts-node, tsx, or build via tsc.
•
Watch paths/aliases.
•
Check production run (without ts-node).
What is the difference between ESM and CommonJS in the context of TypeScript?
•
ESM uses import/export at runtime.
•
CJS uses require/module.exports.
•
TS can emit both variants.
•
In Node, package.json type and extensions .mts/.cts are important.
•
Errors often due to mixing systems.
How to configure TypeScript for Node ESM (NodeNext)?
•
module: NodeNext and moduleResolution: NodeNext.
•
Set type: module in package.json.
•
Use extensions/exports correctly.
•
For types, use .d.ts or .mts.
•
Check build and run together.
How to type Express middleware?
•
Install @types/express.
•
Types for Request, Response, NextFunction.
•
Extend Request via declaration merging if adding fields.
•
Make explicit types for body/query/params.
•
Validate input data.
How to type DTOs and validate input data?
•
TS types do not validate at runtime.
•
Use zod/yup/class-validator.
•
Schema should be the source of truth.
•
Generate type from schema if library allows.
•
Keep validator at system boundary (API).
How to safely work with external data: JSON, API, localStorage?
•
Read everything external as unknown.
•
Validate structure (schema/type guards).
•
Handle missing fields and versioning.
•
Log parsing errors and fallbacks.
•
Do not do as without checks.
How to type localStorage and type conversions?
•
localStorage stores strings.
•
Create functions getJSON<T>() with unknown + validator.
•
For numbers/booleans — explicit conversion.
•
Handle missing keys.
•
Version storage format.
How to properly type errors for domain logic?
•
Create your own error classes (extends Error).
•
Add code/type of cause.
•
Catch and map at top layer (API/UI).
•
Do not throw strings.
•
Document what errors are possible.
What are the typical anti-patterns in TypeScript to avoid?
•
any and chains of as as.
•
! instead of checks.
•
Complex types for the sake of types without benefit.
•
Duplicating DTOs instead of utility functions like Pick/Omit.
•
'Magic' in types without tests and examples.
How to write maintainable types: practical rules?
•
Start with simple types, complicate as needed.
•
Validate at system boundaries at runtime.
•
Do not hide problems with any/as.
•
Use discriminated unions for states.
•
Maintain a consistent style and type checks in CI.
TypeScript — Programming — Technology — FAQ Портал