<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Alex</title>
    <description>The latest articles on DEV Community by Alex (@alexefimenko).</description>
    <link>https://dev.to/alexefimenko</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F222410%2F27eb6c52-0290-464f-a825-1444fe5fd0ac.png</url>
      <title>DEV Community: Alex</title>
      <link>https://dev.to/alexefimenko</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/alexefimenko"/>
    <language>en</language>
    <item>
      <title>I Analyzed Dozens of AI Agent Rules Files. Most Are Making Your Agent Worse.</title>
      <dc:creator>Alex</dc:creator>
      <pubDate>Sat, 14 Mar 2026 20:02:03 +0000</pubDate>
      <link>https://dev.to/alexefimenko/i-analyzed-a-lot-of-ai-agent-rules-files-most-are-making-your-agent-worse-2fl</link>
      <guid>https://dev.to/alexefimenko/i-analyzed-a-lot-of-ai-agent-rules-files-most-are-making-your-agent-worse-2fl</guid>
      <description>&lt;p&gt;An &lt;a href="https://arxiv.org/html/2602.11988v1" rel="noopener noreferrer"&gt;ETH Zurich study from February 2026&lt;/a&gt; tested something most of us assumed was helping: giving AI coding agents a rules file.&lt;/p&gt;

&lt;p&gt;The results were not what anyone expected.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;LLM-generated rules files: &lt;strong&gt;-3% task success rate, +20% cost&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Human-written rules files: &lt;strong&gt;+4% success rate, but +19% cost&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;No rules file at all was the baseline&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The researchers' conclusion: &lt;em&gt;"Omit LLM-generated context files entirely and limit human-written instructions to non-inferable details."&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;In other words — the rules file most developers copy-paste from cursor.directory or generate with ChatGPT is actively making their AI agent slower, more expensive, and less accurate.&lt;/p&gt;

&lt;p&gt;I wanted to understand why, so I crawled thousands of rules files from GitHub and analyzed them. Here's what I found.&lt;/p&gt;

&lt;h2&gt;
  
  
  The four types of rules (and why only one matters)
&lt;/h2&gt;

&lt;p&gt;Every rule in your rules file falls into one of four tiers:&lt;/p&gt;

&lt;h3&gt;
  
  
  Essential
&lt;/h3&gt;

&lt;p&gt;The agent &lt;strong&gt;cannot&lt;/strong&gt; discover this from your code or config files. Remove it and the agent &lt;strong&gt;will&lt;/strong&gt; make wrong decisions.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;- Use pnpm, never npm or yarn
- Auth uses custom middleware chain, not Express standard
- All API responses must use the envelope format from lib/api-response.ts
- Bugs are tracked in Linear project "BACKEND" — reference ticket IDs in commits
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The litmus test: run the agent without this rule. Does it make a mistake that no project file could have prevented? If yes — it's essential.&lt;/p&gt;

&lt;h3&gt;
  
  
  Helpful
&lt;/h3&gt;

&lt;p&gt;The agent &lt;strong&gt;could&lt;/strong&gt; figure this out by reading multiple files, but the rule saves significant exploration time.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;- Prefer server actions for mutations, not API routes
- Use the cn() utility (clsx + twMerge) for conditional class merging
- Test files go in __tests__/ directories, not alongside source
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;These are worth keeping. They save the agent from reading 10 files to infer what one line could tell it.&lt;/p&gt;

&lt;h3&gt;
  
  
  Redundant
&lt;/h3&gt;

&lt;p&gt;The agent detects this &lt;strong&gt;automatically&lt;/strong&gt; from standard project files. These waste context window tokens.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="err"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;Use&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;TypeScript&lt;/span&gt;&lt;span class="w"&gt;                    &lt;/span&gt;&lt;span class="err"&gt;←&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;tsconfig.json&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;exists&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="err"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;This&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;project&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;uses&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;React&lt;/span&gt;&lt;span class="w"&gt;           &lt;/span&gt;&lt;span class="err"&gt;←&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;package.json&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;says&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;so&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="err"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;Use&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;ESLint&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;linting&lt;/span&gt;&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="err"&gt;←&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;.eslintrc.json&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;exists&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="err"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;The&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;project&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;uses&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="err"&gt;-space&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;indent&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="err"&gt;←&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;.prettierrc&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;says&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;so&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Every one of these burns tokens that could hold conversation history or code context instead. Delete them.&lt;/p&gt;

&lt;h3&gt;
  
  
  Improve Codebase
&lt;/h3&gt;

&lt;p&gt;This shouldn't be an AI instruction at all. It should be a linter rule, a config flag, or a CI check.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="err"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;Don't&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;use&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;var&lt;/span&gt;&lt;span class="w"&gt;                      &lt;/span&gt;&lt;span class="err"&gt;←&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;Add&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;ESLint&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;no-var&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;rule&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="err"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;Use&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;strict&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;mode&lt;/span&gt;&lt;span class="w"&gt;                    &lt;/span&gt;&lt;span class="err"&gt;←&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;Set&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;strict:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;in&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;tsconfig.json&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="err"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;Always&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;run&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;tests&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;before&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;commits&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="err"&gt;←&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;Set&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;up&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;husky&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;pre-commit&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;hook&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="err"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;Use&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;meaningful&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;variable&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;names&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="err"&gt;←&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;Add&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;ESLint&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;naming-convention&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;rule&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The key distinction: &lt;strong&gt;detection vs. enforcement&lt;/strong&gt;. "This project uses pnpm" is redundant (the lockfile reveals it). "Always use pnpm, never npm" is essential — it enforces a preference the agent can't infer from files alone.&lt;/p&gt;

&lt;h2&gt;
  
  
  Real example: before and after
&lt;/h2&gt;

&lt;p&gt;Here's a typical rules file I found on GitHub (anonymized, but representative of hundreds I analyzed):&lt;/p&gt;

&lt;h3&gt;
  
  
  Before (28 rules)
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;&lt;span class="gh"&gt;# Project Rules&lt;/span&gt;

&lt;span class="gu"&gt;## General&lt;/span&gt;
&lt;span class="p"&gt;-&lt;/span&gt; Use TypeScript
&lt;span class="p"&gt;-&lt;/span&gt; Use React with Next.js
&lt;span class="p"&gt;-&lt;/span&gt; Write clean, maintainable code
&lt;span class="p"&gt;-&lt;/span&gt; Follow best practices
&lt;span class="p"&gt;-&lt;/span&gt; Use functional components

&lt;span class="gu"&gt;## Code Style&lt;/span&gt;
&lt;span class="p"&gt;-&lt;/span&gt; Use 2-space indentation
&lt;span class="p"&gt;-&lt;/span&gt; Use single quotes
&lt;span class="p"&gt;-&lt;/span&gt; Use semicolons
&lt;span class="p"&gt;-&lt;/span&gt; Use camelCase for variables
&lt;span class="p"&gt;-&lt;/span&gt; Use PascalCase for components
&lt;span class="p"&gt;-&lt;/span&gt; Prefer const over let, never use var

&lt;span class="gu"&gt;## Architecture&lt;/span&gt;
&lt;span class="p"&gt;-&lt;/span&gt; Use the App Router
&lt;span class="p"&gt;-&lt;/span&gt; Use server actions for mutations, not API routes
&lt;span class="p"&gt;-&lt;/span&gt; Separate business logic from API routes
&lt;span class="p"&gt;-&lt;/span&gt; Use the repository pattern for data access

&lt;span class="gu"&gt;## Error Handling&lt;/span&gt;
&lt;span class="p"&gt;-&lt;/span&gt; Always handle errors properly
&lt;span class="p"&gt;-&lt;/span&gt; Use try-catch blocks
&lt;span class="p"&gt;-&lt;/span&gt; Never silently swallow errors

&lt;span class="gu"&gt;## Testing&lt;/span&gt;
&lt;span class="p"&gt;-&lt;/span&gt; Write tests for all new features
&lt;span class="p"&gt;-&lt;/span&gt; Use Vitest for unit tests
&lt;span class="p"&gt;-&lt;/span&gt; Mock external dependencies

&lt;span class="gu"&gt;## Performance&lt;/span&gt;
&lt;span class="p"&gt;-&lt;/span&gt; Use React.memo for expensive components
&lt;span class="p"&gt;-&lt;/span&gt; Lazy load routes
&lt;span class="p"&gt;-&lt;/span&gt; Optimize images with next/image
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;How does this break down?&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Essential:&lt;/strong&gt; 3 rules (server actions for mutations, repository pattern, separate business logic)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Helpful:&lt;/strong&gt; 7 rules (Vitest, mock externals, React.memo, lazy load, next/image, camelCase, PascalCase)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Redundant:&lt;/strong&gt; 8 rules (Use TypeScript, Use React, Use Next.js, App Router, functional components, write clean code, follow best practices, write tests)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Improve Codebase:&lt;/strong&gt; 7 rules (2-space indent, single quotes, semicolons, no var, handle errors, try-catch, never swallow errors)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Over half the file is noise.&lt;/strong&gt; 15 out of 28 rules either duplicate what the agent already knows or belong in tooling config.&lt;/p&gt;

&lt;h3&gt;
  
  
  After (11 rules)
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;&lt;span class="gh"&gt;# Project Rules&lt;/span&gt;
&lt;span class="p"&gt;
-&lt;/span&gt; Use pnpm, never npm or yarn
&lt;span class="p"&gt;-&lt;/span&gt; Use server actions for mutations, not API routes
&lt;span class="p"&gt;-&lt;/span&gt; Separate business logic from API routes into /lib/services/
&lt;span class="p"&gt;-&lt;/span&gt; Use the repository pattern — all DB access goes through /lib/repositories/
&lt;span class="p"&gt;-&lt;/span&gt; API responses use the envelope format: { success, data, error, meta }
&lt;span class="p"&gt;-&lt;/span&gt; Error handling: use neverthrow Result types, not try-catch
&lt;span class="p"&gt;-&lt;/span&gt; All new endpoints need Zod schema validation in /lib/validations.ts
&lt;span class="p"&gt;-&lt;/span&gt; Test with Vitest — mock external deps, never mock the database
&lt;span class="p"&gt;-&lt;/span&gt; Use next/image for all images, enforce WebP format
&lt;span class="p"&gt;-&lt;/span&gt; Commits follow conventional format: feat|fix|refactor: description
&lt;span class="p"&gt;-&lt;/span&gt; Never import from @prisma/client directly — use the db wrapper from /lib/db
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Every rule here is something the agent &lt;strong&gt;cannot infer&lt;/strong&gt; from project files, or would waste significant time discovering. The file is 60% smaller and every line changes agent behavior.&lt;/p&gt;

&lt;h2&gt;
  
  
  The context window problem
&lt;/h2&gt;

&lt;p&gt;Why does this matter so much? Because of how LLM context windows work.&lt;/p&gt;

&lt;p&gt;Your rules file, conversation history, code context, and the AI's own reasoning all share the same fixed-size window. A 200-line rules file with 15 essential lines and 185 lines of noise means:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Token waste&lt;/strong&gt; — you're paying for the AI to read instructions it doesn't need&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Attention dilution&lt;/strong&gt; — research shows LLMs pay less attention to content in the middle of long contexts (the "lost in the middle" effect). Your essential rules get buried between redundant ones.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Reduced code context&lt;/strong&gt; — every token spent on "Use TypeScript" is a token that can't hold actual code the agent needs to understand&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The ETH Zurich numbers make sense when you think about it this way. A bloated rules file doesn't just fail to help — it actively competes with useful context for the agent's attention.&lt;/p&gt;

&lt;h2&gt;
  
  
  How to audit your own rules file
&lt;/h2&gt;

&lt;p&gt;Take your current &lt;code&gt;.cursorrules&lt;/code&gt;, &lt;code&gt;CLAUDE.md&lt;/code&gt;, or &lt;code&gt;AGENTS.md&lt;/code&gt; and ask three questions about each rule:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. Can the agent see this in a config file?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;If &lt;code&gt;tsconfig.json&lt;/code&gt;, &lt;code&gt;package.json&lt;/code&gt;, &lt;code&gt;.eslintrc&lt;/code&gt;, &lt;code&gt;biome.json&lt;/code&gt;, &lt;code&gt;.prettierrc&lt;/code&gt;, or any other standard config already expresses this — delete the rule.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. Is this enforceable by tooling?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;If a linter rule, formatter config, git hook, or CI check can enforce this deterministically — move it there. Don't ask an AI to enforce what a tool can guarantee.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. Would removing this rule cause the agent to make a wrong decision?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;If the answer is "no, it would just take longer" — it's helpful, keep it but don't stress about the wording. If the answer is "yes, it would produce incorrect code" — that's essential, make it precise and specific.&lt;/p&gt;

&lt;h2&gt;
  
  
  What actually changes AI behavior
&lt;/h2&gt;

&lt;p&gt;Addy Osmani's research found that specific tool mentions in context files increase agent usage from 0.01 to 1.6 times per task. The pattern is clear: &lt;strong&gt;specificity drives behavior change&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Rules that work:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;- Use server actions for mutations, not API routes
- All dates stored as UTC in the database, converted to local only in the UI layer
- Never import from @prisma/client directly — use the typed wrapper from /lib/db
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Rules that don't:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;- Write clean code
- Follow best practices
- Handle errors properly
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The difference is degrees of freedom. "Handle errors properly" gives the agent infinite valid interpretations. "Use neverthrow Result types, never try-catch in service functions" gives it exactly one path.&lt;/p&gt;

&lt;h2&gt;
  
  
  I built a tool to automate this
&lt;/h2&gt;

&lt;p&gt;After classifying rules by hand, I got tired and built &lt;a href="https://agentrulegen.com" rel="noopener noreferrer"&gt;Agent Rules Builder&lt;/a&gt; — a free tool that does this automatically.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The Analyzer&lt;/strong&gt; is the feature I use most. Paste your existing rules file, and the AI classifies every single rule into the four tiers — with a quality score, reasoning, and concrete suggestions. For "Improve Codebase" rules, it tells you exactly what linter rule or config flag to add instead. &lt;/p&gt;

&lt;p&gt;It also catches cross-cutting issues: near-duplicate rules, contradictions, vague rules, and security problems like accidentally exposed API keys or internal paths.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F246fi6w0oasz959bcshl.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F246fi6w0oasz959bcshl.png" alt="Agent rule analyzer"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The Builder&lt;/strong&gt; is for when you're starting from scratch or setting up a new project. Pick your language (67 supported), select your framework, and browse a library of 10,000+ rules organized by category — Architecture, Testing, Security, Performance, Error Handling, Agent Workflow, and more.&lt;/p&gt;

&lt;p&gt;What makes it different from template directories: every rule has (or can have) community votes. Other developers upvote or downvote individual rules — not whole files, each rule separately. Bad rules sink, good ones surface on the trending page. &lt;/p&gt;

&lt;p&gt;And each rule gets an &lt;strong&gt;AI quality assessment&lt;/strong&gt; — classified as essential, helpful, redundant, or improve-codebase with a score from 1-10 — so you can see at a glance whether a rule justifies its context window cost before you add it.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffova7gwof80zllpkkmm5.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffova7gwof80zllpkkmm5.png" alt="Agent rule builder with assessment"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You can edit rules directly, add your own, choose between three verbosity levels, and export to any format.&lt;/p&gt;

&lt;h2&gt;
  
  
  The takeaway
&lt;/h2&gt;

&lt;p&gt;Most rules files hurt more than they help because they're full of instructions the AI doesn't need. The fix is simple:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Delete anything the agent can read from config files&lt;/li&gt;
&lt;li&gt;Move anything enforceable to linter/formatter/CI&lt;/li&gt;
&lt;li&gt;Keep only what the agent genuinely can't infer&lt;/li&gt;
&lt;li&gt;Make every remaining rule specific enough to have one interpretation&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;A 10-line file of essential rules beats a 200-line file of copy-pasted advice every time.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>agents</category>
      <category>productivity</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Just for Fun: Create a Battery Indicator with React (Works Only in Chrome)</title>
      <dc:creator>Alex</dc:creator>
      <pubDate>Tue, 19 Mar 2024 02:44:24 +0000</pubDate>
      <link>https://dev.to/alexefimenko/just-for-fun-create-a-battery-indicator-with-react-works-only-in-chrome-2b0n</link>
      <guid>https://dev.to/alexefimenko/just-for-fun-create-a-battery-indicator-with-react-works-only-in-chrome-2b0n</guid>
      <description>&lt;p&gt;In this article, we’re going to build a fun project — a battery indicator component using React. This component will show you the current battery level and whether your device is charging.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fd2kikvhyfvcqe7lgmlnc.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fd2kikvhyfvcqe7lgmlnc.png" alt="Green battery" width="193" height="113"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;However, our battery indicator will rely on the &lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/Navigator/getBattery" rel="noopener noreferrer"&gt;&lt;code&gt;Navigator.getBattery()&lt;/code&gt;&lt;/a&gt; method to retrieve battery information which is &lt;strong&gt;not supported by Mozilla and Safari&lt;/strong&gt; browsers. And also it’s available only in secure contexts (HTTPS).&lt;/p&gt;

&lt;p&gt;This means that our component will only work on Chrome and other Chromium-based browsers like Edge.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fuj5y0pg9tgcsbfto6sny.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fuj5y0pg9tgcsbfto6sny.png" alt="getBattery function browser compatibility" width="720" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;So, that’s why it’s more of a fun project than a practical one.&lt;/p&gt;

&lt;p&gt;Let’s get started!&lt;/p&gt;

&lt;h2&gt;
  
  
  1. Create a new React project using Vite and the React template.
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3c2iefvmy46a4tekc60z.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3c2iefvmy46a4tekc60z.png" alt="Vite logo" width="720" height="300"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Run the following commands to create a new React project using Vite and the React template.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="nx"&gt;npm&lt;/span&gt; &lt;span class="nx"&gt;create&lt;/span&gt; &lt;span class="nx"&gt;vite&lt;/span&gt;&lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;latest&lt;/span&gt; &lt;span class="nx"&gt;battery&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;indicator&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nx"&gt;template&lt;/span&gt; &lt;span class="nx"&gt;react&lt;/span&gt;
&lt;span class="nx"&gt;cd&lt;/span&gt; &lt;span class="nx"&gt;battery&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;indicator&lt;/span&gt;
&lt;span class="nx"&gt;npm&lt;/span&gt; &lt;span class="nx"&gt;install&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  2. Install Tailwind CSS.
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffjc5n508lvxp1nx0ijg6.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffjc5n508lvxp1nx0ijg6.png" alt="Tailwind CSS Logo" width="528" height="101"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We’ll use Tailwind CSS to style our battery indicator component. Run the following commands to install Tailwind CSS and its dependencies.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="nx"&gt;npm&lt;/span&gt; &lt;span class="nx"&gt;install&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;D&lt;/span&gt; &lt;span class="nx"&gt;tailwindcss&lt;/span&gt; &lt;span class="nx"&gt;postcss&lt;/span&gt; &lt;span class="nx"&gt;autoprefixer&lt;/span&gt;
&lt;span class="nx"&gt;npx&lt;/span&gt; &lt;span class="nx"&gt;tailwindcss&lt;/span&gt; &lt;span class="nx"&gt;init&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;p&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Update the &lt;code&gt;tailwind.config.js&lt;/code&gt; file to include the following:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="cm"&gt;/** @type {import('tailwindcss').Config} */&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;content&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./index.html&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./src/**/*.{js,ts,jsx}&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
  &lt;span class="na"&gt;theme&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;extend&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{},&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="na"&gt;plugins&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[],&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then add &lt;code&gt;@tailwind&lt;/code&gt; directives on top of the &lt;code&gt;src/index.css&lt;/code&gt; file.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;tailwind&lt;/span&gt; &lt;span class="nx"&gt;base&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;tailwind&lt;/span&gt; &lt;span class="nx"&gt;components&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;tailwind&lt;/span&gt; &lt;span class="nx"&gt;utilities&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  3. Create the battery indicator component.
&lt;/h2&gt;

&lt;p&gt;Create a new file called &lt;code&gt;BatteryIndicator.jsx&lt;/code&gt; in the &lt;code&gt;src/components&lt;/code&gt; folder. This file will contain the battery indicator component.&lt;/p&gt;

&lt;p&gt;Let’s start with the battery info state and a function to update the battery info.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Initial battery info: battery level: 0-100, charging status: true/false, supported by the browser: true/false &lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;initialBatteryInfo&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;level&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;charging&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;supported&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="c1"&gt;// Battery info state&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;batteryInfo&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setBatteryInfo&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;initialBatteryInfo&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// Update the battery info&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;updateBatteryInfo&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;battery&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;setBatteryInfo&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;level&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;battery&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;level&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;charging&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;battery&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;charging&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;supported&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We have to be sure that the browser supports the Battery Status API before we can use it. To do this, we can check if the &lt;code&gt;getBattery&lt;/code&gt; method is available in the &lt;code&gt;navigator&lt;/code&gt; object by &lt;code&gt;navigator.getBattery&lt;/code&gt;. If it’s available, we can use it to get the battery status. If it’s not, we set the &lt;code&gt;supported&lt;/code&gt; property of the battery info state to &lt;code&gt;false&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Then, we use the &lt;code&gt;useEffect&lt;/code&gt; hook to check if the browser supports the Battery Status API and setup the event listeners for the battery status changes.&lt;/p&gt;

&lt;p&gt;The function that provides the battery status is &lt;code&gt;navigator.getBattery()&lt;/code&gt;. It’s an async function so we need to use await to resolve it.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="nf"&gt;useEffect&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// Check if the browser supports the Battery Status API and setup the event listeners&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;checkBatteryAPIAndSetup&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;navigator&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;getBattery&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// Get the battery status&lt;/span&gt;
        &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;battery&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nb"&gt;navigator&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getBattery&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
        &lt;span class="nf"&gt;updateBatteryInfo&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;battery&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

        &lt;span class="c1"&gt;// Setup the event listeners for the battery status changes&lt;/span&gt;
        &lt;span class="nx"&gt;battery&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addEventListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;chargingchange&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;updateBatteryInfo&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;battery&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
        &lt;span class="nx"&gt;battery&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addEventListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;levelchange&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;updateBatteryInfo&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;battery&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Battery status is not supported.&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="nf"&gt;setBatteryInfo&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;prev&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;prev&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;supported&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt; &lt;span class="p"&gt;}));&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Battery status is not supported.&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="nf"&gt;setBatteryInfo&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;prev&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;prev&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;supported&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt; &lt;span class="p"&gt;}));&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;};&lt;/span&gt;

  &lt;span class="nf"&gt;checkBatteryAPIAndSetup&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;[]);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, let’s create the UI for the battery indicator component. It will consist of the battery level bar, the battery level text, and the charging icon.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Component to display the battery info&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;BatteryInfo&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;batteryInfo&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt; &lt;span class="nx"&gt;className&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s2"&gt;`w-32 h-14 border-2 &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;batteryInfo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;charging&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;border-green-500&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;border-gray-500&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; rounded-lg flex items-center justify-start overflow-hidden relative`&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="cm"&gt;/* Battery level bar */&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt;
        &lt;span class="nx"&gt;className&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;batteryInfo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;level&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;20&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;bg-green-300&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;bg-red-500&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; h-full`&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="nx"&gt;style&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{{&lt;/span&gt; &lt;span class="na"&gt;width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;batteryInfo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;level&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;%`&lt;/span&gt; &lt;span class="p"&gt;}}&lt;/span&gt;
      &lt;span class="o"&gt;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;      &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="cm"&gt;/* Battery level text */&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt; &lt;span class="nx"&gt;className&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;absolute w-full h-full flex items-center justify-center text-lg font-semibold&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;batteryInfo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;level&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toFixed&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)}&lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt;
      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;      &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;batteryInfo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;charging&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;ChargingIcon&lt;/span&gt; &lt;span class="o"&gt;/&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The battery level bar has width that corresponds to the battery level. We use the &lt;code&gt;style&lt;/code&gt; attribute to set the width of the bar based on the battery level. We use the &lt;code&gt;toFixed&lt;/code&gt; method to round the battery level to the nearest whole number.&lt;/p&gt;

&lt;p&gt;Simple logic is used to determine the color of the battery level bar based on the battery level. If the battery level is greater than 20%, the bar will be green, otherwise, it will be red.&lt;/p&gt;

&lt;p&gt;We also show the charging icon if the device is charging:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;ChargingIcon&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;svg&lt;/span&gt; &lt;span class="nx"&gt;className&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;absolute right-0 mr-[-6px] w-6 h-6 text-green-500&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="nx"&gt;fill&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;none&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="nx"&gt;viewBox&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;0 0 24 24&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="nx"&gt;stroke&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;currentColor&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;path&lt;/span&gt; &lt;span class="nx"&gt;strokeLinecap&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;round&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="nx"&gt;strokeLinejoin&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;round&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="nx"&gt;strokeWidth&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="nx"&gt;d&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;M11 7L6 12h4v8l5-5h-4v-8z&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/svg&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, let’s put it all together in the &lt;code&gt;BatteryIndicator&lt;/code&gt; component:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;useEffect&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;react&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// Initial battery info: battery level: 0-100, charging status: true/false, supported by the browser: true/false &lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;initialBatteryInfo&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;level&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;12&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;charging&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;supported&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;BatteryIndicator&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;batteryInfo&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setBatteryInfo&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;initialBatteryInfo&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="c1"&gt;// Update the battery info&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;updateBatteryInfo&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;battery&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;setBatteryInfo&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;level&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;battery&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;level&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;charging&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;battery&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;charging&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;supported&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="p"&gt;};&lt;/span&gt;

  &lt;span class="nf"&gt;useEffect&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// Check if the browser supports the Battery Status API and setup the event listeners&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;checkBatteryAPIAndSetup&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;navigator&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;getBattery&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="c1"&gt;// Get the battery status&lt;/span&gt;
          &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;battery&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nb"&gt;navigator&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getBattery&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
          &lt;span class="nf"&gt;updateBatteryInfo&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;battery&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

          &lt;span class="c1"&gt;// Setup the event listeners for the battery status changes&lt;/span&gt;
          &lt;span class="nx"&gt;battery&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addEventListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;chargingchange&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;updateBatteryInfo&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;battery&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
          &lt;span class="nx"&gt;battery&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addEventListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;levelchange&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;updateBatteryInfo&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;battery&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Battery status is not supported.&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
          &lt;span class="nf"&gt;setBatteryInfo&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;prev&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;prev&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;supported&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt; &lt;span class="p"&gt;}));&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Battery status is not supported.&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="nf"&gt;setBatteryInfo&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;prev&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;prev&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;supported&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt; &lt;span class="p"&gt;}));&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;};&lt;/span&gt;

    &lt;span class="nf"&gt;checkBatteryAPIAndSetup&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;[]);&lt;/span&gt;

  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt; &lt;span class="nx"&gt;className&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;flex items-center justify-center h-screen&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt; &lt;span class="nx"&gt;className&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;text-center&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;batteryInfo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;supported&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt; &lt;span class="nx"&gt;className&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;flex flex-col items-center justify-center space-y-2&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
          &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;BatteryInfo&lt;/span&gt; &lt;span class="nx"&gt;batteryInfo&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;batteryInfo&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;      &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt; &lt;span class="nx"&gt;className&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;p-4 rounded-md bg-gray-200 text-gray-700&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
          &lt;span class="nx"&gt;Battery&lt;/span&gt; &lt;span class="nx"&gt;status&lt;/span&gt; &lt;span class="k"&gt;is&lt;/span&gt; &lt;span class="nx"&gt;not&lt;/span&gt; &lt;span class="nx"&gt;supported&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt; &lt;span class="nx"&gt;browser&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;      &lt;span class="p"&gt;)}&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;  &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;So, our component is ready. Now, let’s import it into the &lt;code&gt;App&lt;/code&gt; component, remove anything else, and see it in action.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;BatteryIndicator&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./components/BatteryIndicator&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;App&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;BatteryIndicator&lt;/span&gt; &lt;span class="o"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nx"&gt;App&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, run the following command to start the development server and open the app in your browser.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="nx"&gt;npm&lt;/span&gt; &lt;span class="nx"&gt;run&lt;/span&gt; &lt;span class="nx"&gt;dev&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Open &lt;a href="http://localhost:5173/" rel="noopener noreferrer"&gt;localhost:5173&lt;/a&gt; in your browser. You should see the battery indicator component showing the current battery level and whether your device is charging.&lt;/p&gt;

&lt;p&gt;If your device is charging you should see a charging icon on the right side of the battery level bar.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fd2kikvhyfvcqe7lgmlnc.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fd2kikvhyfvcqe7lgmlnc.png" alt="Green battery" width="193" height="113"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If the battery level is less than 20% the battery level bar will be red:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fipw5edott0iin40bwlfr.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fipw5edott0iin40bwlfr.png" alt="Red battery" width="192" height="110"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If the battery status is not supported in your browser, you should see a message saying “Battery status is not supported in this browser.”&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjlj46saxp5mzsv7bhnlq.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjlj46saxp5mzsv7bhnlq.png" alt="Battery status is not supported in this browser message" width="407" height="101"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;That’s it! You’ve created a battery indicator component using React. It’s a fun project that works only in Chrome and other Chromium-based browsers like Edge. It’s not practical, but it’s a fun way to learn about the Battery Status API and how to use it in a React app.&lt;/p&gt;

&lt;h2&gt;
  
  
  References
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://github.com/aleksandr-efimenko/battery-indicator-react" rel="noopener noreferrer"&gt;GitHub repository of the code from this article&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://battery-indicator-react.vercel.app/" rel="noopener noreferrer"&gt;Live demo of the app from this article&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Originally posted &lt;a href="https://medium.com/@alexefimenko/just-for-fun-create-a-battery-indicator-with-react-works-only-in-chrome-cba6027c33f2" rel="noopener noreferrer"&gt;on Medium&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I’m always looking to meet new people in tech. Feel free to &lt;a href="https://www.linkedin.com/in/aleksandr-efimenko" rel="noopener noreferrer"&gt;connect with me on LinkedIn&lt;/a&gt;!&lt;/p&gt;

</description>
      <category>react</category>
      <category>javascript</category>
      <category>webdev</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>TypeScript Index Signatures: 4 Examples Type-Safe Dynamic Objects</title>
      <dc:creator>Alex</dc:creator>
      <pubDate>Wed, 13 Mar 2024 01:25:07 +0000</pubDate>
      <link>https://dev.to/alexefimenko/typescript-index-signatures-4-examples-type-safe-dynamic-objects-554o</link>
      <guid>https://dev.to/alexefimenko/typescript-index-signatures-4-examples-type-safe-dynamic-objects-554o</guid>
      <description>&lt;p&gt;In TypeScript, &lt;strong&gt;index signatures&lt;/strong&gt; are a powerful feature that allows you to type objects with unknown structures.&lt;/p&gt;

&lt;p&gt;They are especially useful when you want to define a type for objects with unknown properties or when you want to create a dictionary-like data structure.&lt;/p&gt;

&lt;p&gt;Additionally, index signatures are often used to create complex utility types that can be used to manipulate and transform other types.&lt;/p&gt;

&lt;h2&gt;
  
  
  What are Index Signatures?
&lt;/h2&gt;

&lt;p&gt;An index signature defines a type for the values that an object can have at a particular index (key). It specifies a contract between the keys and the values of an object.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;MyInterface&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this example, the index signature &lt;code&gt;[key: string]&lt;/code&gt; defines that any key of type &lt;code&gt;string&lt;/code&gt; will have a corresponding value of type &lt;code&gt;number&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;This means that any object implementing the &lt;code&gt;MyInterface&lt;/code&gt; interface can have any number of string keys, and the values associated with those keys must be numbers.&lt;/p&gt;

&lt;h2&gt;
  
  
  Example 1: String-to-String Dictionary
&lt;/h2&gt;

&lt;p&gt;Let’s say you want to create a simple dictionary that maps language codes (like “en”, “fr”, “es”) to their full English names (“English”, “French”, “Spanish”). With an index signature, you can define a type for this dictionary that allows for any number of language codes as keys, but ensures that all values are strings.&lt;/p&gt;

&lt;p&gt;Define the Dictionary interface:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;LanguageDictionary&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now we are sure that any string can be used as a key and all values are also strings:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;languages&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;LanguageDictionary&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;en&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;English&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;fr&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;French&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;es&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Spanish&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="c1"&gt;// You can add more languages without changing the type&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="c1"&gt;// Adding a new language to the dictionary&lt;/span&gt;
&lt;span class="nx"&gt;languages&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;de&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;German&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// Retrieving a language name&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;languages&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;en&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// Output: "English"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Example 2: Product Inventory Object
&lt;/h2&gt;

&lt;p&gt;Suppose you are building an e-commerce application and you want to represent a product inventory object that has a fixed set of properties (name, price) and a dynamic set of properties (stock for different sizes).&lt;/p&gt;

&lt;p&gt;You can use an index signature to define a type for this object that allows for a fixed set of properties and a dynamic set of properties.&lt;/p&gt;

&lt;p&gt;To maintain strict type safety without mixing specific properties with index signatures when their types differ, it’s better to separate the concerns.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Bad example of mixing properties with index signatures&lt;/span&gt;
&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;BadProduct&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;price&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="c1"&gt;// Error - Property 'name' of type 'string' is not assignable to 'string' index type 'number'&lt;/span&gt;
  &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="na"&gt;size&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; 
&lt;span class="p"&gt;}&lt;/span&gt;


&lt;span class="c1"&gt;// Better solution - It's immediately clear which parts of the object are fixed and which parts are dynamic.&lt;/span&gt;
&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;Product&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;price&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;stock&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="na"&gt;size&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this example the &lt;code&gt;name&lt;/code&gt; and &lt;code&gt;price&lt;/code&gt; fields maintain their strict types, separate from the dynamically typed &lt;code&gt;stock&lt;/code&gt; object.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;tShirt&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Product&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;T-Shirt&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;price&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;20&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;stock&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;S&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;M&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;15&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;L&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="c1"&gt;// Accessing the 'M' stock value using nested object with bracket notation&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;product1&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;stock&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;M&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt; &lt;span class="c1"&gt;// Output: 15&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This pattern is scalable and can be extended to include other dynamic properties if needed, by adding more nested objects or arrays with their specific types.&lt;/p&gt;

&lt;h2&gt;
  
  
  Example 3: Creating a Custom Utility Type
&lt;/h2&gt;

&lt;p&gt;Index signatures are essential in TypeScript for creating complex utility types because they allow for flexible and dynamic data structures while maintaining type safety.&lt;/p&gt;

&lt;p&gt;Suppose you have a type representing a user with several properties, and you want to create a new type where all of these properties are optional.&lt;/p&gt;

&lt;p&gt;There is built-in utility type &lt;code&gt;Partial&lt;/code&gt; that does exactly that. Earlier, &lt;a href="https://medium.com/@alexefimenko/7-highly-effective-typescript-utility-types-9770b5360821" rel="noopener noreferrer"&gt;I wrote about TypeScript utility types&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;However, for understanding of index signatures, let’s create a custom utility type &lt;code&gt;Optional&lt;/code&gt; that does the same thing.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;User&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;age&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;email&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;Optional&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;K&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="kr"&gt;keyof&lt;/span&gt; &lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="p"&gt;]?:&lt;/span&gt; &lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;K&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;OptionalUser&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;Optional&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;User&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// OptionalUser is equivalent to:&lt;/span&gt;
&lt;span class="c1"&gt;// type OptionalUser = {&lt;/span&gt;
&lt;span class="c1"&gt;//   id?: number | undefined;&lt;/span&gt;
&lt;span class="c1"&gt;//   name?: string | undefined;&lt;/span&gt;
&lt;span class="c1"&gt;//   age?: number | undefined;&lt;/span&gt;
&lt;span class="c1"&gt;//   email?: string | undefined;&lt;/span&gt;
&lt;span class="c1"&gt;// }&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the above example, we created a custom utility type &lt;code&gt;Optional&lt;/code&gt; that takes a type &lt;code&gt;T&lt;/code&gt; and returns a new type where all properties of &lt;code&gt;T&lt;/code&gt; are optional.&lt;/p&gt;

&lt;p&gt;Here we use index signatures to iterate over the keys of &lt;code&gt;T&lt;/code&gt; and make each property optional by adding a &lt;code&gt;?&lt;/code&gt; after the property name.&lt;/p&gt;

&lt;p&gt;This allows us to create a new type &lt;code&gt;OptionalUser&lt;/code&gt; that has all the properties of &lt;code&gt;User&lt;/code&gt; but with each property being optional.&lt;/p&gt;

&lt;h2&gt;
  
  
  Example 4: API response with dynamic keys
&lt;/h2&gt;

&lt;p&gt;When working with APIs, you often receive data with a fixed set of properties and a dynamic set of properties. Index signatures are useful for defining types for such data.&lt;/p&gt;

&lt;p&gt;Suppose you have an API that returns a response with a fixed set of properties (status, message) and a dynamic set of properties (data for different resources).&lt;/p&gt;

&lt;p&gt;You can use an index signature to define a type for this response that allows for a fixed set of properties and a dynamic set of properties.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;ApiResponse&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;status&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;message&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="na"&gt;resource&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt; &lt;span class="kr"&gt;any&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;ApiResponse&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;status&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;success&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;message&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Data fetched successfully&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;users&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[{&lt;/span&gt; &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;John&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Doe&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;}],&lt;/span&gt;
  &lt;span class="na"&gt;products&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[{&lt;/span&gt; &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Laptop&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;price&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1000&lt;/span&gt; &lt;span class="p"&gt;}],&lt;/span&gt;
  &lt;span class="c1"&gt;// You can add more resources without changing the type&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this example, the &lt;code&gt;ApiResponse&lt;/code&gt; type has a fixed set of properties (status, message) and an index signature &lt;code&gt;[resource: string]&lt;/code&gt; that allows for any number of dynamic properties with any value type.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Index signatures are a powerful feature in TypeScript that allows you to define types for objects with unknown structures. They are especially useful when you want to create dictionary-like data structures or when you want to define complex utility types.&lt;/p&gt;

&lt;p&gt;I hope this article has given you a good understanding of how to use index signatures in TypeScript and how they can be used to create complex and flexible types. If you have any questions or feedback, feel free to leave a comment below.&lt;/p&gt;

&lt;p&gt;Check out my other TypeScript articles:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://dev.to/alexefimenko/3-examples-of-typescript-generic-react-components-4f9"&gt;Making React Components More Flexible with TypeScript Generics: 3 Examples&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/alexefimenko/5-resources-each-typescript-developer-should-know-about-30m4"&gt;5 Resources Each TypeScript Developer Should Know About&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/alexefimenko/typescript-enums-5-real-world-use-cases-4idk"&gt;TypeScript Enums: 5 Real-World Use Cases&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This article was originally &lt;a href="https://medium.com/@alexefimenko/typescript-index-signatures-build-type-safe-dynamic-objects-0082dc3372c9" rel="noopener noreferrer"&gt;posted on Medium&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>typescript</category>
      <category>webdev</category>
      <category>javascript</category>
      <category>node</category>
    </item>
    <item>
      <title>Making React Components More Flexible with TypeScript Generics: 3 Examples</title>
      <dc:creator>Alex</dc:creator>
      <pubDate>Tue, 12 Mar 2024 13:00:00 +0000</pubDate>
      <link>https://dev.to/alexefimenko/3-examples-of-typescript-generic-react-components-4f9</link>
      <guid>https://dev.to/alexefimenko/3-examples-of-typescript-generic-react-components-4f9</guid>
      <description>&lt;p&gt;Generic React components allow you to create a component that can be used with any data type. This is a great way to create reusable components that can be used in multiple places in your application.&lt;/p&gt;

&lt;p&gt;There are a lot of articles and tutorials on generics in TypeScript, so I will focus on how to use generics in React components to make them more flexible and reusable.&lt;/p&gt;

&lt;h2&gt;
  
  
  Example 1: Simple Generic React Component (easy to understand)
&lt;/h2&gt;

&lt;p&gt;In this example, we will create a generic React component that can be used with any data type.&lt;/p&gt;

&lt;p&gt;To clarify generics' benefits, we will create a component with data of type &lt;code&gt;T&lt;/code&gt; and a render function.&lt;/p&gt;

&lt;h3&gt;
  
  
  Create a Generic React Component
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Define a generic type for the props&lt;/span&gt;
&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;Props&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;T&lt;/span&gt;
  &lt;span class="na"&gt;render&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="na"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ReactNode&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// Create a generic React component&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;GenericComponent&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;render&lt;/span&gt; &lt;span class="p"&gt;}:&lt;/span&gt; &lt;span class="nx"&gt;Props&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nf"&gt;render&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)}&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here, &lt;code&gt;GenericComponent&lt;/code&gt; accepts prop render, which is a function that takes data of type &lt;code&gt;T&lt;/code&gt; and returns a &lt;code&gt;React.ReactNode&lt;/code&gt;. This pattern, often called “render props,” gives you more control over how the data is rendered.&lt;/p&gt;

&lt;p&gt;Next, we use &lt;code&gt;GenericComponent&lt;/code&gt; with different types of data, showing how TypeScript ensures that the types are used consistently.&lt;/p&gt;

&lt;h3&gt;
  
  
  Use the GenericComponent with a string
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;GenericComponent&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./GenericComponent&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;RenderString&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;GenericComponent&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; 
    &lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Hello, world!&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; 
    &lt;span class="nx"&gt;render&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{(&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;span&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toUpperCase&lt;/span&gt;&lt;span class="p"&gt;()}&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/span&amp;gt;}&lt;/span&gt;&lt;span class="err"&gt; 
&lt;/span&gt;  &lt;span class="o"&gt;/&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here, &lt;code&gt;GenericComponent&lt;/code&gt; is explicitly told to expect a string. The render function converts the string to uppercase, which is a valid operation on strings. TypeScript ensures that the operations you perform in the render prop are appropriate for the type of data passed.&lt;/p&gt;

&lt;h3&gt;
  
  
  Use the GenericComponent with a custom type
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;Person&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;
  &lt;span class="na"&gt;age&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;GenericComponent&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./GenericComponent&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;RenderPerson&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;GenericComponent&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Person&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{{&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Alice&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;age&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;30&lt;/span&gt; &lt;span class="p"&gt;}}&lt;/span&gt;
      &lt;span class="nx"&gt;render&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{(&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;span&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
          &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;is&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;age&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="nx"&gt;years&lt;/span&gt; &lt;span class="nx"&gt;old&lt;/span&gt;
        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/span&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;      &lt;span class="p"&gt;)}&lt;/span&gt;
    &lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;  &lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this case, TypeScript ensures that the data prop matches the type expected by the render function.&lt;/p&gt;

&lt;p&gt;Let’s move on to a more complex example. We will create a generic component that can be used with a list of items.&lt;/p&gt;

&lt;h3&gt;
  
  
  Use the GenericComponent with a List of Todos
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;useState&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;react&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;GenericComponent&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./GenericComponent&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;TodoItem&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;
  &lt;span class="nx"&gt;title&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;
  &lt;span class="nx"&gt;completed&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;boolean&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;TodoList&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// Initial list of todos&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;initialTodos&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;TodoItem&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;title&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Learn React&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;completed&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;title&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Write blog post&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;completed&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;title&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Study TypeScript&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;completed&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;]&lt;/span&gt;

  &lt;span class="c1"&gt;// State to track todos&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;todos&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setTodos&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;useState&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;TodoItem&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;initialTodos&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

  &lt;span class="c1"&gt;// Function to toggle the completion status of a todo item&lt;/span&gt;
  &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;toggleTodoCompletion&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;updatedTodos&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;todos&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;todo&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; 
        &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;todo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="nx"&gt;id&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;todo&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;completed&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;todo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;completed&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;todo&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="nf"&gt;setTodos&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;updatedTodos&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="c1"&gt;// Complex render function for a list of TodoItems&lt;/span&gt;
  &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;renderTodos&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;todos&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;TodoItem&lt;/span&gt;&lt;span class="p"&gt;[])&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;ul&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;todos&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;todo&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
          &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;li&lt;/span&gt;
            &lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;todo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
            &lt;span class="nx"&gt;style&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{{&lt;/span&gt; &lt;span class="na"&gt;textDecoration&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;todo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;completed&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;line-through&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;none&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;cursor&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;pointer&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;}}&lt;/span&gt;
            &lt;span class="nx"&gt;onClick&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;toggleTodoCompletion&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;todo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;)}&lt;/span&gt;
          &lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;todo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;title&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
          &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/li&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;        &lt;span class="p"&gt;))}&lt;/span&gt;
      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/ul&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;    &lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;GenericComponent&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;TodoItem&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;  
    &lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;todos&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; 
    &lt;span class="nx"&gt;render&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;renderTodos&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; 
  &lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this example, we create a &lt;code&gt;TodoList&lt;/code&gt; component that uses &lt;code&gt;GenericComponent&lt;/code&gt; to render a list of &lt;code&gt;TodoItems&lt;/code&gt;. The render function is more complex, as it needs to handle a list of items. TypeScript ensures that the data prop matches the type expected by the render function.&lt;/p&gt;

&lt;p&gt;In the next example, the benefits of generics will be more clear. We will create a generic component that fetches data from an API and displays it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Example 2: Generic React Component to Fetch and Display Data
&lt;/h2&gt;

&lt;p&gt;In this example, we will create a generic React component that fetches data from an API and displays it. This is so often used in real-world applications that it’s a great example of how generics can make your components more flexible and reusable.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdv8arqmde50to3yl6h1k.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdv8arqmde50to3yl6h1k.png" alt="JSONPlaceholder banner" width="800" height="251"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Create a Generic React Component to Fetch Data
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;useEffect&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;useState&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;react&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="c1"&gt;// Define a generic type for the props&lt;/span&gt;
&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;Props&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;url&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;
  &lt;span class="na"&gt;render&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="na"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ReactNode&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// Create a generic React component&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;FetchAndDisplay&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;render&lt;/span&gt; &lt;span class="p"&gt;}:&lt;/span&gt; &lt;span class="nx"&gt;Props&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setData&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;useState&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;loading&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setLoading&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setError&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;useState&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nb"&gt;Error&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

  &lt;span class="nf"&gt;useEffect&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;fetchData&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ok&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Failed to fetch data&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;json&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="nf"&gt;setData&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;json&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nf"&gt;setError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;finally&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nf"&gt;setLoading&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="nf"&gt;fetchData&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;

  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;loading&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;Loading&lt;/span&gt;&lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nb"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nf"&gt;render&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)}&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this example, &lt;code&gt;FetchAndDisplay&lt;/code&gt; is a generic component that accepts a URL and a render function. It uses the &lt;code&gt;fetch&lt;/code&gt;to make a request to the URL and then calls the render function with the data. The component also handles loading and error states.&lt;/p&gt;

&lt;h3&gt;
  
  
  Using the FetchAndDisplay component to Fetch and Display Posts
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;FetchAndDisplay&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./FetchAndDisplay&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;Post&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;userId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;
  &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;
  &lt;span class="na"&gt;title&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;
  &lt;span class="na"&gt;body&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;RenderPosts&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;posts&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Post&lt;/span&gt;&lt;span class="p"&gt;[])&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;ul&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;posts&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;post&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;li&lt;/span&gt; &lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;post&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
          &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;h3&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;post&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;title&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/h3&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;          &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;p&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;post&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/p&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/li&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;      &lt;span class="p"&gt;))}&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/ul&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;  &lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;PostList&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;FetchAndDisplay&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Post&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; 
    &lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;https://jsonplaceholder.typicode.com/posts&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;  
    &lt;span class="nx"&gt;render&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;RenderPosts&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; 
  &lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this example, we use the &lt;code&gt;FetchAndDisplay&lt;/code&gt; component to fetch a list of posts from the JSONPlaceholder API and then render them using the &lt;code&gt;RenderPosts&lt;/code&gt; function. &lt;/p&gt;

&lt;p&gt;Having the generic component &lt;code&gt;FetchAndDisplay&lt;/code&gt; allows us to fetch and display data from any API and render it in any way we want.&lt;/p&gt;

&lt;p&gt;For example, we can use the same component to fetch and display a list of users, comments, or any other type of data.&lt;/p&gt;

&lt;h3&gt;
  
  
  Using the FetchAndDisplay component to Fetch and Display Users
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;FetchAndDisplay&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./FetchAndDisplay&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;User&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;
  &lt;span class="na"&gt;email&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;RenderUsers&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;users&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;User&lt;/span&gt;&lt;span class="p"&gt;[])&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;ul&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;users&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;li&lt;/span&gt; &lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
          &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;h3&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/h3&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;          &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;p&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;email&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/p&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/li&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;      &lt;span class="p"&gt;))}&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/ul&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;  &lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;UserList&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;FetchAndDisplay&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;User&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; 
    &lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;https://jsonplaceholder.typicode.com/users&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; 
    &lt;span class="nx"&gt;render&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;RenderUsers&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; 
  &lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here, we use the same &lt;code&gt;FetchAndDisplay&lt;/code&gt; component to fetch a list of users from the JSONPlaceholder API and then render them using the &lt;code&gt;RenderUsers&lt;/code&gt; function. This is the power of generics in React components.&lt;/p&gt;

&lt;h2&gt;
  
  
  Example 3: Generic React Component for Form Input
&lt;/h2&gt;

&lt;p&gt;This example demonstrates how to create a generic form component that can be used with different types of form fields. &lt;/p&gt;

&lt;p&gt;In real-world applications, I would use a library like &lt;strong&gt;Formik&lt;/strong&gt; or &lt;strong&gt;react-hook-form&lt;/strong&gt; for form handling, but to demonstrate generics, we will create a simple form component from scratch.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhqthhislta4262y6joaz.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhqthhislta4262y6joaz.png" alt="Form example" width="432" height="393"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;First, define TypeScript types to specify the structure of your form fields and the props your generic form component will accept. This ensures type safety and helps manage the form’s state and behavior.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;
&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;FormField&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;
  &lt;span class="na"&gt;label&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;
  &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;text&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;email&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;password&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="c1"&gt;// Extend as needed&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;GenericFormProps&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;fields&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;FormField&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;
  &lt;span class="na"&gt;initialValues&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;T&lt;/span&gt;
  &lt;span class="na"&gt;onSubmit&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="na"&gt;values&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Next, create a functional component that takes in fields, initial values, and an &lt;code&gt;onSubmit&lt;/code&gt; function.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;useState&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;react&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;GenericForm&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;fields&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;initialValues&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;onSubmit&lt;/span&gt; &lt;span class="p"&gt;}:&lt;/span&gt; &lt;span class="nx"&gt;GenericFormProps&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;values&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setValues&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;useState&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;initialValues&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

  &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;handleChange&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ChangeEvent&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;HTMLInputElement&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;value&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;target&lt;/span&gt;
    &lt;span class="nf"&gt;setValues&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;prevValues&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;prevValues&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt; &lt;span class="nx"&gt;value&lt;/span&gt; &lt;span class="p"&gt;}))&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;handleSubmit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;FormEvent&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;HTMLFormElement&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;preventDefault&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="nf"&gt;onSubmit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;values&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;form&lt;/span&gt; &lt;span class="nx"&gt;onSubmit&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;handleSubmit&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;fields&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;field&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt; &lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;field&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
          &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;label&lt;/span&gt; &lt;span class="nx"&gt;htmlFor&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;field&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;field&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;label&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/label&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;          &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;input&lt;/span&gt; &lt;span class="kd"&gt;type&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;field&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="kd"&gt;type&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;field&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; 
                 &lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{(&lt;/span&gt;&lt;span class="nx"&gt;values&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="kr"&gt;any&lt;/span&gt;&lt;span class="p"&gt;)[&lt;/span&gt;&lt;span class="nx"&gt;field&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;]}&lt;/span&gt; 
                 &lt;span class="nx"&gt;onChange&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;handleChange&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;      &lt;span class="p"&gt;))}&lt;/span&gt;
      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;button&lt;/span&gt; &lt;span class="kd"&gt;type&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;submit&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;Submit&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/button&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/form&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;  &lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Finally, use the GenericForm component with specific form fields and initial values.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;
&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;UserFormValues&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;
  &lt;span class="na"&gt;email&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;
  &lt;span class="na"&gt;password&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;userFormFields&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;FormField&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;name&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;label&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Name&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;text&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;email&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;label&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Email&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;email&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;password&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;label&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Password&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;password&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;]&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;initialValues&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;UserFormValues&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;''&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;email&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;''&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;password&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;''&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;App&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;handleSubmit&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;values&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;UserFormValues&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Form Submitted&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;values&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;h1&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;User&lt;/span&gt; &lt;span class="nx"&gt;Registration&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/h1&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;GenericForm&lt;/span&gt; 
        &lt;span class="nx"&gt;fields&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;userFormFields&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; 
        &lt;span class="nx"&gt;initialValues&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;initialValues&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; 
        &lt;span class="nx"&gt;onSubmit&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;handleSubmit&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; 
      &lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;  &lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this example, without using generics, you would have to create a separate form component for each type of form. With generics, you can create a single form component that can be used with any type of form fields.&lt;/p&gt;

&lt;h2&gt;
  
  
  Bonus Example: Table Component with Generics
&lt;/h2&gt;

&lt;p&gt;This example is taken from the video:&lt;/p&gt;

&lt;p&gt;  &lt;iframe src="https://www.youtube.com/embed/zqz-lEHjJr4"&gt;
  &lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;In the example, the table component is made generic by adding a type parameter called &lt;code&gt;TRow&lt;/code&gt;. This &lt;code&gt;TRow&lt;/code&gt; parameter represents the type of data that will be in each row of the table.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;Table&lt;/code&gt; component takes in an array of rows and a &lt;code&gt;renderRow&lt;/code&gt; function. The &lt;code&gt;renderRow&lt;/code&gt; function is called for each row in the array and is responsible for rendering the row.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;Table&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;TRow&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nb"&gt;Record&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kr"&gt;any&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;rows&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;TRow&lt;/span&gt;&lt;span class="p"&gt;[];&lt;/span&gt;
  &lt;span class="nl"&gt;renderRow&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;FC&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;TRow&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;table&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;tbody&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;rows&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;row&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
          &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;renderRow&lt;/span&gt; &lt;span class="p"&gt;{...&lt;/span&gt;&lt;span class="nx"&gt;row&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;        &lt;span class="p"&gt;))}&lt;/span&gt;
      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/tbody&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/table&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;  &lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this example, the &lt;code&gt;Table&lt;/code&gt; component takes in an array of rows and a &lt;code&gt;renderRow&lt;/code&gt; function. The &lt;code&gt;renderRow&lt;/code&gt; function is called for each row in the array and is responsible for rendering the row.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Table&lt;/span&gt;
  &lt;span class="nx"&gt;rows&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{[&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Alice&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;age&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;30&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Bob&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;age&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;40&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;]}&lt;/span&gt;
  &lt;span class="nx"&gt;renderRow&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{({&lt;/span&gt; &lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;age&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;tr&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;td&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/td&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;td&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;age&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/td&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/tr&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;  &lt;span class="p"&gt;)}&lt;/span&gt;
&lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this example, the &lt;code&gt;Table&lt;/code&gt; component is used to render a table with two rows, each containing a name and an age. The &lt;code&gt;TRow&lt;/code&gt; type parameter ensures that the rows array and the renderRow function are used consistently.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Generics are a powerful feature of TypeScript that can make your React components more flexible and reusable. They allow you to create components that can be used with any data type, which is especially useful in real-world applications where you often need to work with different types of data.&lt;/p&gt;

&lt;p&gt;I hope this article has given you a good understanding of how to use generics in React components and how they can make your components more flexible and reusable. If you have any questions or feedback, please feel free to leave a comment below.&lt;/p&gt;

&lt;h2&gt;
  
  
  Helpful Resources
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://www.typescriptlang.org/docs/handbook/2/generics.html" rel="noopener noreferrer"&gt;TypeScript Generics&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://react-typescript-cheatsheet.netlify.app/docs/basic/getting-started/basic_type_example" rel="noopener noreferrer"&gt;React TypeScript Cheatsheet&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://www.youtube.com/@mattpocockuk" rel="noopener noreferrer"&gt;Matt Pocock's channel on YouTube&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Check out my other articles on TypeScript:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://dev.to/alexefimenko/typescript-index-signatures-4-examples-type-safe-dynamic-objects-554o"&gt;TypeScript Index Signatures: 4 Examples Type-Safe Dynamic Objects&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/alexefimenko/5-resources-each-typescript-developer-should-know-about-30m4"&gt;5 Resources Each TypeScript Developer Should Know About&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/alexefimenko/typescript-enums-5-real-world-use-cases-4idk"&gt;TypeScript Enums: 5 Real-World Use Cases&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This article was originally &lt;a href="https://medium.com/@alexefimenko/3-examples-of-typescript-generic-react-components-3b186d9d5402" rel="noopener noreferrer"&gt;posted on Medium&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>typescript</category>
      <category>webdev</category>
      <category>javascript</category>
      <category>react</category>
    </item>
    <item>
      <title>TypeScript Enums: 5 Real-World Use Cases</title>
      <dc:creator>Alex</dc:creator>
      <pubDate>Tue, 12 Mar 2024 01:29:40 +0000</pubDate>
      <link>https://dev.to/alexefimenko/typescript-enums-5-real-world-use-cases-4idk</link>
      <guid>https://dev.to/alexefimenko/typescript-enums-5-real-world-use-cases-4idk</guid>
      <description>&lt;p&gt;If you’re looking to make your TypeScript code more organized, enums are a powerful tool. They group related values together, giving your code better structure and readability. Let’s dive in and explore how to use them!&lt;/p&gt;

&lt;p&gt;In TypeScript, enums are declared using the &lt;code&gt;enum&lt;/code&gt; keyword. For example, you could create an enum to represent the different fruit prices as follows:&lt;/p&gt;

&lt;h2&gt;
  
  
  Example 1: Basic Enum Structure — Key Movements
&lt;/h2&gt;

&lt;p&gt;Demonstrates a common use case for enums: making choices within a limited set clearer.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kr"&gt;enum&lt;/span&gt; &lt;span class="nx"&gt;Movement&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;Up&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;UP&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;Down&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;DOWN&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;Left&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;LEFT&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;Right&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;RIGHT&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;handlePlayerInput&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;switch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="nx"&gt;Movement&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Up&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
     &lt;span class="c1"&gt;// Move player character up&lt;/span&gt;
      &lt;span class="k"&gt;break&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="nx"&gt;Movement&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Down&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
      &lt;span class="c1"&gt;// Move player character down&lt;/span&gt;
      &lt;span class="k"&gt;break&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="c1"&gt;// ... other cases&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This demonstrates the fundamental syntax for defining an enum. The &lt;code&gt;Movement&lt;/code&gt; enum has four members representing directions.&lt;/p&gt;

&lt;h2&gt;
  
  
  Example 2: Enums with Values
&lt;/h2&gt;

&lt;p&gt;Enums can have associated values (numbers, strings, etc.). Here, &lt;code&gt;StatusCode&lt;/code&gt; associates HTTP status codes, ensuring type-safety and preventing the use of arbitrary numbers.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kr"&gt;enum&lt;/span&gt; &lt;span class="nx"&gt;StatusCode&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;OK&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;BadRequest&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;400&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;NotFound&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;404&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;handleResponse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;code&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;StatusCode&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;code&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="nx"&gt;StatusCode&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;OK&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// Handle successful response&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;code&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="nx"&gt;StatusCode&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;NotFound&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// Handle resource not found&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; 
  &lt;span class="c1"&gt;// ... other cases&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F19dr3ztmspzsc43fflzf.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F19dr3ztmspzsc43fflzf.png" alt="HTTP status codes" width="720" height="377"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Image source: &lt;a href="https://restfulapi.net/http-status-codes/" rel="noopener noreferrer"&gt;https://restfulapi.net/http-status-codes&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Example 3: Enum from Redux Toolkit
&lt;/h2&gt;

&lt;p&gt;Redux Toolkit is a popular library for state management in React applications. It makes heavy use of TypeScript for type safety.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fo2rle1vdipn595j86z0j.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fo2rle1vdipn595j86z0j.png" alt="Redux logo" width="720" height="119"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This enum defines distinct states for asynchronous actions (like fetching data). This is common in state management libraries.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kr"&gt;enum&lt;/span&gt; &lt;span class="nx"&gt;PayloadActionLoadingState&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;Idle&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;idle&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;Loading&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;loading&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;Failed&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;failed&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;Success&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;success&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; 
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Example 4: Enum as a Discriminated Union
&lt;/h2&gt;

&lt;p&gt;This enum defines two possible shapes: &lt;code&gt;Circle&lt;/code&gt; and &lt;code&gt;Rectangle&lt;/code&gt;. It acts as a foundation for ensuring type safety when working with different shapes.&lt;/p&gt;

&lt;p&gt;Each shape type (&lt;code&gt;Circle&lt;/code&gt;, &lt;code&gt;Rectangle&lt;/code&gt;) is represented as a member of the &lt;code&gt;ShapeType&lt;/code&gt; enum.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;Shape&lt;/code&gt; interface has a &lt;code&gt;type&lt;/code&gt; property that must be a member of the &lt;code&gt;ShapeType&lt;/code&gt; enum.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kr"&gt;enum&lt;/span&gt; &lt;span class="nx"&gt;ShapeType&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;Circle&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Circle&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;Rectangle&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Rectangle&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;Shape&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;ShapeType&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; 
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;Circle&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nx"&gt;Shape&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;ShapeType&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Circle&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;radius&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;Rectangle&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nx"&gt;Shape&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;ShapeType&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Rectangle&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;height&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;calculateArea&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;shape&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Shape&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;switch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;shape&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="kd"&gt;type&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="nx"&gt;ShapeType&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Circle&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;circle&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;shape&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;Circle&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// Type assertion to Circle&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;PI&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nx"&gt;circle&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;radius&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nx"&gt;circle&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;radius&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="nx"&gt;ShapeType&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Rectangle&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;rectangle&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;shape&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;Rectangle&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// Type assertion to Rectangle&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;rectangle&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;width&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nx"&gt;rectangle&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;height&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="nl"&gt;default&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Invalid shape type&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Specific shape interfaces (&lt;code&gt;Circle&lt;/code&gt;, &lt;code&gt;Rectangle&lt;/code&gt;) extend the base &lt;code&gt;Shape&lt;/code&gt; interface and must have their &lt;code&gt;type&lt;/code&gt; property set to the corresponding enum value.&lt;/p&gt;

&lt;p&gt;This lets the &lt;code&gt;calculateArea&lt;/code&gt; function use the &lt;code&gt;type&lt;/code&gt; property as a discriminator to determine the appropriate calculation.&lt;/p&gt;

&lt;h2&gt;
  
  
  Example 5: Enums as Data Structures
&lt;/h2&gt;

&lt;p&gt;This TypeScript code defines a simple model for representing playing cards, focusing on the suits, ranks, and the color of the card, which is derived from its suit.&lt;/p&gt;

&lt;p&gt;It consists of two enums, a function to get a card’s numerical value, an interface to describe a card’s structure, and a function to create a card.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kr"&gt;enum&lt;/span&gt; &lt;span class="nx"&gt;Suit&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;Hearts&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;♥&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;// Red suit&lt;/span&gt;
  &lt;span class="nx"&gt;Diamonds&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;♦&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;// Red suit&lt;/span&gt;
  &lt;span class="nx"&gt;Clubs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;♣&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;// Black suit&lt;/span&gt;
  &lt;span class="nx"&gt;Spades&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;♠&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="c1"&gt;// Black suit&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kr"&gt;enum&lt;/span&gt; &lt;span class="nx"&gt;Rank&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;Ace&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;Two&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;Three&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;Four&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;Five&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;Six&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;Seven&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;Eight&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;Nine&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;Ten&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;Jack&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;Queen&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;King&lt;/span&gt; 
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;getCardValue&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;rank&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Rank&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;rank&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="nx"&gt;Rank&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Ten&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;rank&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;Card&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;suit&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Suit&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;rank&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Rank&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// Derived property based on suit&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;createCard&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;suit&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Suit&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;rank&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Rank&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nx"&gt;Card&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;suit&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;rank&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;suit&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="nx"&gt;Suit&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Hearts&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nx"&gt;suit&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="nx"&gt;Suit&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Diamonds&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Red&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Black&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// Usage&lt;/span&gt;
&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;card1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;createCard&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;Suit&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Hearts&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;Rank&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Ace&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`The Ace of Hearts is red: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;card1&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;color&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// Output: The Ace of Hearts is red: Red&lt;/span&gt;

&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;card2&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;createCard&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;Suit&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Spades&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;Rank&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Queen&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`The Queen of Spades is black: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;card2&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;color&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// Output: The Queen of Spades is black: Black&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Function &lt;code&gt;getCardValue&lt;/code&gt; takes a &lt;code&gt;Rank&lt;/code&gt; as an argument and returns a number. For ranks &lt;code&gt;Ace&lt;/code&gt; through &lt;code&gt;Ten&lt;/code&gt; (numerically 1 to 10), it returns the rank's numeric value. For face cards (&lt;code&gt;Jack&lt;/code&gt;, &lt;code&gt;Queen&lt;/code&gt;, &lt;code&gt;King&lt;/code&gt;), which have rank values greater than 10, it returns 10.&lt;/p&gt;

&lt;p&gt;Two card objects are created using the &lt;code&gt;createCard&lt;/code&gt; function:  &lt;code&gt;card1&lt;/code&gt; as the Ace of Hearts (which is red) and &lt;code&gt;card2&lt;/code&gt; as the Queen of Spades (which is black).&lt;/p&gt;

&lt;p&gt;This code is a straightforward way to model the basic properties of playing cards in a type-safe manner using TypeScript’s features like enums, interfaces, and type inference.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Enums provide a solid foundation for clean and structured TypeScript code. As your projects grow in complexity, their benefits will continue to shine.&lt;/p&gt;

&lt;p&gt;TypeScript enums are a powerful tool to elevate your code. They enhance readability, maintainability, and type safety.&lt;/p&gt;

&lt;p&gt;Check out my other TypeScript articles:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://dev.to/alexefimenko/typescript-index-signatures-4-examples-type-safe-dynamic-objects-554o"&gt;TypeScript Index Signatures: 4 Examples Type-Safe Dynamic Objects&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/alexefimenko/3-examples-of-typescript-generic-react-components-4f9"&gt;Making React Components More Flexible with TypeScript Generics: 3 Examples&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/alexefimenko/5-resources-each-typescript-developer-should-know-about-30m4"&gt;5 Resources Each TypeScript Developer Should Know About&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This article was originally &lt;a href="https://medium.com/@alexefimenko/typescript-enums-5-real-world-use-cases-7ceccc423c18" rel="noopener noreferrer"&gt;posted on Medium&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>typescript</category>
      <category>webdev</category>
      <category>javascript</category>
      <category>programming</category>
    </item>
    <item>
      <title>5 Resources Each TypeScript Developer Should Know About</title>
      <dc:creator>Alex</dc:creator>
      <pubDate>Sun, 10 Mar 2024 21:03:47 +0000</pubDate>
      <link>https://dev.to/alexefimenko/5-resources-each-typescript-developer-should-know-about-30m4</link>
      <guid>https://dev.to/alexefimenko/5-resources-each-typescript-developer-should-know-about-30m4</guid>
      <description>&lt;p&gt;Want to become a TypeScript pro? Master advanced TypeScript skills with these resources, from type definitions and challenging type puzzles to practical utility libraries and API development tools.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. DefinitelyTyped — A collection of type definitions
&lt;/h2&gt;

&lt;p&gt;DefinitelyTyped serves as a community-driven collection of high-quality TypeScript type definitions. &lt;/p&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://assets.dev.to/assets/github-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/DefinitelyTyped" rel="noopener noreferrer"&gt;
        DefinitelyTyped
      &lt;/a&gt; / &lt;a href="https://github.com/DefinitelyTyped/DefinitelyTyped" rel="noopener noreferrer"&gt;
        DefinitelyTyped
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      The repository for high quality TypeScript type definitions.
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;
&lt;div class="markdown-heading"&gt;
&lt;h1 class="heading-element"&gt;Definitely Typed&lt;/h1&gt;
&lt;/div&gt;
&lt;blockquote&gt;
&lt;p&gt;The repository for &lt;em&gt;high quality&lt;/em&gt; TypeScript type definitions.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;em&gt;You can also read this README in &lt;a href="https://github.com/DefinitelyTyped/DefinitelyTyped/blob/master/README.es.md" rel="noopener noreferrer"&gt;Español&lt;/a&gt;, &lt;a href="https://github.com/DefinitelyTyped/DefinitelyTyped/blob/master/README.ko.md" rel="noopener noreferrer"&gt;한국어&lt;/a&gt;, &lt;a href="https://github.com/DefinitelyTyped/DefinitelyTyped/blob/master/README.ru.md" rel="noopener noreferrer"&gt;Русский&lt;/a&gt;, &lt;a href="https://github.com/DefinitelyTyped/DefinitelyTyped/blob/master/README.zh-Hans.md" rel="noopener noreferrer"&gt;简体中文&lt;/a&gt;, &lt;a href="https://github.com/DefinitelyTyped/DefinitelyTyped/blob/master/README.pt.md" rel="noopener noreferrer"&gt;Português&lt;/a&gt;, &lt;a href="https://github.com/DefinitelyTyped/DefinitelyTyped/blob/master/README.it.md" rel="noopener noreferrer"&gt;Italiano&lt;/a&gt;, &lt;a href="https://github.com/DefinitelyTyped/DefinitelyTyped/blob/master/README.ja.md" rel="noopener noreferrer"&gt;日本語&lt;/a&gt; and &lt;a href="https://github.com/DefinitelyTyped/DefinitelyTyped/blob/master/README.fr.md" rel="noopener noreferrer"&gt;Français&lt;/a&gt;!&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Link to &lt;a href="https://github.com/DefinitelyTyped/DefinitelyTyped/./docs/admin.md" rel="noopener noreferrer"&gt;Admin manual&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;!!! Important! This repo has recently changed layout! !!!&lt;/h2&gt;
&lt;/div&gt;
&lt;p&gt;Definitely Typed has recently changed to a proper &lt;code&gt;pnpm&lt;/code&gt; monorepo; you may want to reread this document for changes to the layout of packages in this repo.&lt;/p&gt;
&lt;p&gt;At the very least, you may want to &lt;code&gt;git clean -fdx&lt;/code&gt; the repo (or &lt;code&gt;node ./scripts/clean-node-modules.js&lt;/code&gt; on Windows) to clean up &lt;code&gt;node_modules&lt;/code&gt; and run &lt;code&gt;pnpm install --filter .&lt;/code&gt; to install the workspace root. See further sections for more info on &lt;code&gt;pnpm install&lt;/code&gt;.&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Current status&lt;/h2&gt;
&lt;/div&gt;
&lt;p&gt;This section tracks the health of the repository and publishing process.
It may be helpful for contributors experiencing any issues with their PRs and packages.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Most recent build &lt;a href="https://github.com/microsoft/DefinitelyTyped-tools/tree/master/packages/dtslint" rel="noopener noreferrer"&gt;type-checked/linted&lt;/a&gt; cleanly: &lt;a href="https://github.com/DefinitelyTyped/DefinitelyTyped/actions/workflows/CI.yml?query=branch%3Amaster+event%3Apush" rel="noopener noreferrer"&gt;&lt;img src="https://github.com/DefinitelyTyped/DefinitelyTyped/actions/workflows/CI.yml/badge.svg?branch=master&amp;amp;event=push" alt="Build status"&gt;&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;All packages…&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
  &lt;/div&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/DefinitelyTyped/DefinitelyTyped" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;


&lt;p&gt;In simple terms, it provides TypeScript interfaces and type information for JavaScript libraries that don’t have them built-in.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvadzh89i6fodqc6fzq2z.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvadzh89i6fodqc6fzq2z.png" alt="DefinitelyTyped Logo" width="256" height="59"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;When you’re using a JavaScript library in a TypeScript project, TypeScript needs to know the shapes and types of the library’s exports to type-check your code correctly.&lt;/p&gt;

&lt;p&gt;It’s highly popular and has over 100 million weekly downloads!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5oo4s3diyrwh0fvlxk6p.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5oo4s3diyrwh0fvlxk6p.png" alt="Weekly downloads DefinitelyTyped npm" width="371" height="85"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This repo allows developers to use existing JavaScript libraries within their TypeScript projects seamlessly, ensuring type safety.&lt;/p&gt;

&lt;p&gt;If the library doesn’t provide its own types, you can likely find them in DefinitelyTyped. These type definitions are then used by the TypeScript compiler to understand the library’s structure, offering auto-completion, type checking, and other IDE features for a smoother development experience.&lt;/p&gt;

&lt;h3&gt;
  
  
  Example (Lodash)
&lt;/h3&gt;

&lt;p&gt;Let’s say you’re working on a TypeScript project and decide to use &lt;strong&gt;Lodash&lt;/strong&gt;, a popular utility library. &lt;strong&gt;Lodash&lt;/strong&gt; itself is written in JavaScript and doesn’t include TypeScript definitions. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ff8oi1s7cjpxndaytog54.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ff8oi1s7cjpxndaytog54.png" alt="Lodash Logo" width="720" height="92"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Here's how you can use Lodash with types in your project with the help of DefinitelyTyped:&lt;/p&gt;

&lt;p&gt;First, install Lodash:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install &lt;/span&gt;lodash
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Then, install the type definitions for Lodash from DefinitelyTyped:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install&lt;/span&gt; @types/lodash &lt;span class="nt"&gt;--save-dev&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Now, you can use Lodash in your TypeScript file with full type support:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;_&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;lodash&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// Example usage with full type support&lt;/span&gt;
&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;numArray&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;sum&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;_&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sum&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;numArray&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// Lodash's sum function&lt;/span&gt;

&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;sum&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// Output will be 15&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;By using DefinitelyTyped's type definitions, you can maintain type safety and take full advantage of TypeScript's features, even when using JavaScript libraries.&lt;/p&gt;
&lt;h2&gt;
  
  
  2. Type Challenges — A collection of TypeScript puzzles
&lt;/h2&gt;

&lt;p&gt;The repo provides a collection of TypeScript puzzles similar to LeetCode problems. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkk3ahyjyhq4stvi75rzx.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkk3ahyjyhq4stvi75rzx.png" alt="Type Challenges Logo" width="800" height="167"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Each challenge focuses on a specific aspect of TypeScript’s type system, from basic concepts to complex type manipulation. You’ll often need to use generic types or apply advanced features like conditional types and mapped types to solve them.&lt;/p&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://assets.dev.to/assets/github-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/type-challenges" rel="noopener noreferrer"&gt;
        type-challenges
      &lt;/a&gt; / &lt;a href="https://github.com/type-challenges/type-challenges" rel="noopener noreferrer"&gt;
        type-challenges
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      Collection of TypeScript type challenges with online judge
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;
&lt;p&gt;
  &lt;a rel="noopener noreferrer" href="https://github.com/type-challenges/type-challenges/./screenshots/logo.svg"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fgithub.com%2Ftype-challenges%2Ftype-challenges%2F.%2Fscreenshots%2Flogo.svg" width="400"&gt;&lt;/a&gt;
&lt;/p&gt;
&lt;p&gt;Collection of TypeScript type challenges&lt;/p&gt;
&lt;p&gt;
  &lt;a href="https://discord.gg/UgKBCq9" rel="nofollow noopener noreferrer"&gt;
    &lt;img src="https://camo.githubusercontent.com/0af8f8b8316de8fc8753980c47437123ef8b2653f103442d2d7c95bb636ee850/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d446973636f72642d79656c6c6f77677265656e3f6c6f676f3d646973636f7264266c6f676f436f6c6f723d776869746526636f6c6f723d373238396461"&gt;
  &lt;/a&gt;
  &lt;a href="https://www.typescriptlang.org/play?install-plugin=%40type-challenges%2Fplayground-plugin" rel="nofollow noopener noreferrer"&gt;
    &lt;img src="https://camo.githubusercontent.com/91ab41f8783f7abe6adb8f8a687209aaae564fea31de66490c3f7d78968fa77d/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f506c617967726f756e642d3134333f6c6f676f3d7479706573637269707426636f6c6f723d333137384336266c6f676f436f6c6f723d666666"&gt;
  &lt;/a&gt;
&lt;/p&gt;
&lt;br&gt;
&lt;p&gt;
  English | &lt;a href="https://github.com/type-challenges/type-challenges/./README.zh-CN.md" rel="noopener noreferrer"&gt;简体中文&lt;/a&gt; | &lt;a href="https://github.com/type-challenges/type-challenges/./README.ja.md" rel="noopener noreferrer"&gt;日本語&lt;/a&gt; | &lt;a href="https://github.com/type-challenges/type-challenges/./README.ko.md" rel="noopener noreferrer"&gt;한국어&lt;/a&gt; | &lt;a href="https://github.com/type-challenges/type-challenges/./README.pt-BR.md" rel="noopener noreferrer"&gt;Português&lt;/a&gt;
&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Intro&lt;/h2&gt;
&lt;/div&gt;

&lt;p&gt;
  &lt;del&gt;&lt;em&gt;by the power of TypeScript's well-known &lt;a href="https://github.com/microsoft/TypeScript/issues/14833" rel="noopener noreferrer"&gt;Turing Completed&lt;/a&gt; type system&lt;/em&gt;&lt;/del&gt;
&lt;/p&gt;

&lt;p&gt;High-quality types can help improve projects' maintainability while avoiding potential bugs.&lt;/p&gt;

&lt;p&gt;This project is aimed at helping you better understand how the type system works, writing your own utilities, or just having fun with the challenges. We are also trying to form a community where you can ask questions and get answers you have faced in the real world - they may become part of the challenges!&lt;/p&gt;

&lt;p&gt;You can also use some existing type utility libraries such as &lt;a href="https://github.com/sindresorhus/type-fest" rel="noopener noreferrer"&gt;type-fest&lt;/a&gt;. There are also some stale packages (not actively maintained) that you could reference, like  &lt;a href="https://github.com/piotrwitek/utility-types" rel="noopener noreferrer"&gt;utility-types&lt;/a&gt;, &lt;a href="https://github.com/millsp/ts-toolbelt" rel="noopener noreferrer"&gt;ts-toolbelt&lt;/a&gt;, &lt;a href="https://github.com/andnp/SimplyTyped" rel="noopener noreferrer"&gt;SimplyTyped&lt;/a&gt;.&lt;/p&gt;

&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Challenges&lt;/h2&gt;
&lt;/div&gt;

&lt;blockquote&gt;
&lt;p&gt;Click the following badges to see details of the challenges.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note&lt;/strong&gt;: Challenges work in the &lt;a href="https://www.typescriptlang.org/tsconfig#strict" rel="nofollow noopener noreferrer"&gt;strict mode&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;



&lt;p&gt;&lt;a rel="noopener noreferrer nofollow" href="https://camo.githubusercontent.com/ed3b2bb7d03d5de6fc02e3abf268fec1f15093879eda76c6151a2f61ef345fe9/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f7761726d2d2d75702d312d7465616c"&gt;&lt;img src="https://camo.githubusercontent.com/ed3b2bb7d03d5de6fc02e3abf268fec1f15093879eda76c6151a2f61ef345fe9/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f7761726d2d2d75702d312d7465616c" alt="1"&gt;&lt;/a&gt;&lt;br&gt;&lt;a href="https://github.com/type-challenges/type-challenges/./questions/00013-warm-hello-world/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/20d4f0290cc69fb1f870b92a84bf51fd1101968590874c12b600438a835be61d/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d313325453325383325424248656c6c6f253230576f726c642d7465616c" alt="13・Hello World"&gt;&lt;/a&gt; &lt;br&gt;&lt;br&gt;&lt;a rel="noopener noreferrer nofollow" href="https://camo.githubusercontent.com/a59e1fcc9741232f6daefbe098cf5ffef3a5304f1515ae5517804e17718c8d03/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f656173792d31332d376161643063"&gt;&lt;img src="https://camo.githubusercontent.com/a59e1fcc9741232f6daefbe098cf5ffef3a5304f1515ae5517804e17718c8d03/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f656173792d31332d376161643063" alt="13"&gt;&lt;/a&gt;&lt;br&gt;&lt;a href="https://github.com/type-challenges/type-challenges/./questions/00004-easy-pick/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/06d0211585b52905434f4e915f8d1a61c87b3c4cb14b229769424442873cc159/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d342545332538332542425069636b2d376161643063" alt="4・Pick"&gt;&lt;/a&gt; &lt;a href="https://github.com/type-challenges/type-challenges/./questions/00007-easy-readonly/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/84c51a27203cd8656e7912ebe93ac836abb21907ed2df8738c26ecc18f9dff81/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d37254533253833254242526561646f6e6c792d376161643063" alt="7・Readonly"&gt;&lt;/a&gt; &lt;a href="https://github.com/type-challenges/type-challenges/./questions/00011-easy-tuple-to-object/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/a484722500934eb028ca5ed7bfa067f88742f9e00abc42e82c65d484ec84f7a7/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d31312545332538332542425475706c65253230746f2532304f626a6563742d376161643063" alt="11・Tuple to Object"&gt;&lt;/a&gt; &lt;a href="https://github.com/type-challenges/type-challenges/./questions/00014-easy-first/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/be13b2c83820d0277a75db97b25288775cedabd995d9deb9ac95602bd9268826/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d313425453325383325424246697273742532306f6625323041727261792d376161643063" alt="14・First of Array"&gt;&lt;/a&gt; &lt;a href="https://github.com/type-challenges/type-challenges/./questions/00018-easy-tuple-length/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/8279ef38dca0d7d1fc42a16153af6cd32ce6a700cb44f1e0e48a7674bf47c865/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d31382545332538332542424c656e6774682532306f662532305475706c652d376161643063" alt="18・Length of Tuple"&gt;&lt;/a&gt; &lt;a href="https://github.com/type-challenges/type-challenges/./questions/00043-easy-exclude/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/ba7e91e317c7798586097785f6fd386eae88932a6dd28dca14c84ab79ce246be/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d34332545332538332542424578636c7564652d376161643063" alt="43・Exclude"&gt;&lt;/a&gt; &lt;a href="https://github.com/type-challenges/type-challenges/./questions/00189-easy-awaited/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/bbef34543a44abf3666ba55e42426fc297fd5d6b30f75e854dcd14cd7f5ef2bf/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d313839254533253833254242417761697465642d376161643063" alt="189・Awaited"&gt;&lt;/a&gt; &lt;a href="https://github.com/type-challenges/type-challenges/./questions/00268-easy-if/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/6b89362f2c82ca2e355aee1f51178613edb1b3ec419ce462a44d2b98792962d4/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d32363825453325383325424249662d376161643063" alt="268・If"&gt;&lt;/a&gt; &lt;a href="https://github.com/type-challenges/type-challenges/./questions/00533-easy-concat/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/f3d5afa6143f18c062ce750649155be904949a04e8b3b36bd2296aa76a02ea06/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d353333254533253833254242436f6e6361742d376161643063" alt="533・Concat"&gt;&lt;/a&gt; &lt;a href="https://github.com/type-challenges/type-challenges/./questions/00898-easy-includes/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/1fc1ad61f4739b83034268e1d06edd172016c082fd0e87ffcc605c08a1d9a89b/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d383938254533253833254242496e636c756465732d376161643063" alt="898・Includes"&gt;&lt;/a&gt; &lt;a href="https://github.com/type-challenges/type-challenges/./questions/03057-easy-push/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/c8b44fb5d8cb9928db8c375c14d5f9235d3a0792a07f3e1ef9d6c21c197b5fa5/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d33303537254533253833254242507573682d376161643063" alt="3057・Push"&gt;&lt;/a&gt; &lt;a href="https://github.com/type-challenges/type-challenges/./questions/03060-easy-unshift/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/df24253c70091cba7830aacd772ced86c5b2231bdecf56c10cb9b54a3f7ec50a/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d33303630254533253833254242556e73686966742d376161643063" alt="3060・Unshift"&gt;&lt;/a&gt; &lt;a href="https://github.com/type-challenges/type-challenges/./questions/03312-easy-parameters/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/08f4f79c8d4705b83ad15c4ed67dcd36ca5f5b7c8a177a756a1883011b655c87/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d33333132254533253833254242506172616d65746572732d376161643063" alt="3312・Parameters"&gt;&lt;/a&gt; &lt;br&gt;&lt;br&gt;&lt;a rel="noopener noreferrer nofollow" href="https://camo.githubusercontent.com/5ce5de1d4b19bca6e7ef6a672f95332c00eb8b60bb4c9ae91a3806e4619968c7/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f6d656469756d2d3130342d643939303161"&gt;&lt;img src="https://camo.githubusercontent.com/5ce5de1d4b19bca6e7ef6a672f95332c00eb8b60bb4c9ae91a3806e4619968c7/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f6d656469756d2d3130342d643939303161" alt="104"&gt;&lt;/a&gt;&lt;br&gt;&lt;a href="https://github.com/type-challenges/type-challenges/./questions/00002-medium-return-type/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/5c65927abde553215dcd6c2509e315c71caee596947155d9035c050ed5432115/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d3225453325383325424247657425323052657475726e253230547970652d643939303161" alt="2・Get Return Type"&gt;&lt;/a&gt; &lt;a href="https://github.com/type-challenges/type-challenges/./questions/00003-medium-omit/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/6b045a5c99e00480c82029e36f594071ef6b5578d3045eae9d430451f874f530/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d332545332538332542424f6d69742d643939303161" alt="3・Omit"&gt;&lt;/a&gt; &lt;a href="https://github.com/type-challenges/type-challenges/./questions/00008-medium-readonly-2/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/f0164a51a8b8ac10a377f5163de611351a0dcfaaae76f5119966e5e71778c5f2/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d38254533253833254242526561646f6e6c79253230322d643939303161" alt="8・Readonly 2"&gt;&lt;/a&gt; &lt;a href="https://github.com/type-challenges/type-challenges/./questions/00009-medium-deep-readonly/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/5f8a5a59fc2ca3e1a95fbe83e5967015270ef541c443c034d3012e87f58ae477/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d3925453325383325424244656570253230526561646f6e6c792d643939303161" alt="9・Deep Readonly"&gt;&lt;/a&gt; &lt;a href="https://github.com/type-challenges/type-challenges/./questions/00010-medium-tuple-to-union/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/49a65bc299035aa497ee2bacabafb5d229e7c7dd36a89ef03f062589a4660187/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d31302545332538332542425475706c65253230746f253230556e696f6e2d643939303161" alt="10・Tuple to Union"&gt;&lt;/a&gt; &lt;a href="https://github.com/type-challenges/type-challenges/./questions/00012-medium-chainable-options/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/aea4b9a471ae9f2c75f0da1814791f612e46272904011b03c043b6bf6de40c5e/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d3132254533253833254242436861696e61626c652532304f7074696f6e732d643939303161" alt="12・Chainable Options"&gt;&lt;/a&gt; &lt;a href="https://github.com/type-challenges/type-challenges/./questions/00015-medium-last/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/1c8b9b0d0c3a942bfbcee84eb951589ef10badac16355d2a9a61f4cadf8c0803/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d31352545332538332542424c6173742532306f6625323041727261792d643939303161" alt="15・Last of Array"&gt;&lt;/a&gt; &lt;a href="https://github.com/type-challenges/type-challenges/./questions/00016-medium-pop/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/17a2698e2af5965bdad2f14843f116630957afc585225f738b5d09d683d21a73/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d3136254533253833254242506f702d643939303161" alt="16・Pop"&gt;&lt;/a&gt; &lt;a href="https://github.com/type-challenges/type-challenges/./questions/00020-medium-promise-all/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/0c813d6ca109d17ef474e45f40902463c168693adcdf0d395b945b50dcb5576c/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d323025453325383325424250726f6d6973652e616c6c2d643939303161" alt="20・Promise.all"&gt;&lt;/a&gt; &lt;a href="https://github.com/type-challenges/type-challenges/./questions/00062-medium-type-lookup/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/23682c391a565041676ad66a5366f0977654629e70a752712502aa4838b93263/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d3632254533253833254242547970652532304c6f6f6b75702d643939303161" alt="62・Type Lookup"&gt;&lt;/a&gt; &lt;a href="https://github.com/type-challenges/type-challenges/./questions/00106-medium-trimleft/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/7841b3c493964ed01e3e03f33e8df8a055eb5aa5990ccd7df85d3011f5065353/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d3130362545332538332542425472696d2532304c6566742d643939303161" alt="106・Trim Left"&gt;&lt;/a&gt; &lt;a href="https://github.com/type-challenges/type-challenges/./questions/00108-medium-trim/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/bd510276112778b8016e77dded00ac4f6a8e6ab52744f25c8e5802534c271f33/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d3130382545332538332542425472696d2d643939303161" alt="108・Trim"&gt;&lt;/a&gt; &lt;a href="https://github.com/type-challenges/type-challenges/./questions/00110-medium-capitalize/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/d350ff0ffe7773395072f6899b50ebe7859f2bf549fa13a0f3f06fc0c7903eec/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d3131302545332538332542424361706974616c697a652d643939303161" alt="110・Capitalize"&gt;&lt;/a&gt; &lt;a href="https://github.com/type-challenges/type-challenges/./questions/00116-medium-replace/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/05dd3dbb2d357c31bbf55b1e069002141e655c7880b873d49a792354bcce6a2f/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d3131362545332538332542425265706c6163652d643939303161" alt="116・Replace"&gt;&lt;/a&gt; &lt;a href="https://github.com/type-challenges/type-challenges/./questions/00119-medium-replaceall/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/0847c57f6e903376f9530e249a7cb14ccc8511d6e7eff4aeeb13495c653e0b84/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d3131392545332538332542425265706c616365416c6c2d643939303161" alt="119・ReplaceAll"&gt;&lt;/a&gt; &lt;a href="https://github.com/type-challenges/type-challenges/./questions/00191-medium-append-argument/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/b5280c1981b5da2422cda461c5adfb7cf63bc238957b9b51ec8bbe962aa9ef87/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d313931254533253833254242417070656e64253230417267756d656e742d643939303161" alt="191・Append Argument"&gt;&lt;/a&gt; &lt;a href="https://github.com/type-challenges/type-challenges/./questions/00296-medium-permutation/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/3e139c166215546579505762aa59ddd12f1aa026c55217b76573028dfc7101d3/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d3239362545332538332542425065726d75746174696f6e2d643939303161" alt="296・Permutation"&gt;&lt;/a&gt; &lt;a href="https://github.com/type-challenges/type-challenges/./questions/00298-medium-length-of-string/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/e521c6ceca0904a0c415ae587fee96bb22e55bbe32cd6d96a1843cd44704c517/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d3239382545332538332542424c656e6774682532306f66253230537472696e672d643939303161" alt="298・Length of String"&gt;&lt;/a&gt; &lt;a href="https://github.com/type-challenges/type-challenges/./questions/00459-medium-flatten/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/e6c829ffc0591d77d2156e97341446b33014b9c1f3d0923f8384fd65c8d6102e/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d343539254533253833254242466c617474656e2d643939303161" alt="459・Flatten"&gt;&lt;/a&gt; &lt;a href="https://github.com/type-challenges/type-challenges/./questions/00527-medium-append-to-object/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/6fa6b24e8d0dcb86fa6497610cc15a5b1f40c1a17bad819538c077cb79b476c6/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d353237254533253833254242417070656e64253230746f2532306f626a6563742d643939303161" alt="527・Append to object"&gt;&lt;/a&gt; &lt;a href="https://github.com/type-challenges/type-challenges/./questions/00529-medium-absolute/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/3d9badff828ae75c1c5159d33cf82985d01125177245d0ac19e32d76072daac0/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d3532392545332538332542424162736f6c7574652d643939303161" alt="529・Absolute"&gt;&lt;/a&gt; &lt;a href="https://github.com/type-challenges/type-challenges/./questions/00531-medium-string-to-union/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/0b5dc7a7d7c838fcd1ed696717da0227f1d3b0cf32ab9d0fa11e9c9b92867fa6/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d353331254533253833254242537472696e67253230746f253230556e696f6e2d643939303161" alt="531・String to Union"&gt;&lt;/a&gt; &lt;a href="https://github.com/type-challenges/type-challenges/./questions/00599-medium-merge/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/80ac0910efa4965ae92d733a5eb961769be84bd936083e0ea8be1a8dea2f3e36/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d3539392545332538332542424d657267652d643939303161" alt="599・Merge"&gt;&lt;/a&gt; &lt;a href="https://github.com/type-challenges/type-challenges/./questions/00612-medium-kebabcase/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/83cc63664548a730af53834ce5daac8a46d17e3e1f688447c49bf8ffeafcae7e/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d3631322545332538332542424b65626162436173652d643939303161" alt="612・KebabCase"&gt;&lt;/a&gt; &lt;a href="https://github.com/type-challenges/type-challenges/./questions/00645-medium-diff/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/5b0fa66b1fe21775c2367877317117481c00a953808ac1bae899e0de300e9c10/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d363435254533253833254242446966662d643939303161" alt="645・Diff"&gt;&lt;/a&gt; &lt;a href="https://github.com/type-challenges/type-challenges/./questions/00949-medium-anyof/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/ec5408aaaa684507be6a071e9a80c52a9696a83df114855f095055e77f67d5a5/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d393439254533253833254242416e794f662d643939303161" alt="949・AnyOf"&gt;&lt;/a&gt; &lt;a href="https://github.com/type-challenges/type-challenges/./questions/01042-medium-isnever/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/21f70ef723fbe60e50214cc9dfe6161d1cb5c5d705432a7af527f0f42a5e1b3b/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d3130343225453325383325424249734e657665722d643939303161" alt="1042・IsNever"&gt;&lt;/a&gt; &lt;a href="https://github.com/type-challenges/type-challenges/./questions/01097-medium-isunion/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/0cbfaea7428701c0e664579f341749da2ee8911a87296c96e4cc691f93606f24/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d313039372545332538332542424973556e696f6e2d643939303161" alt="1097・IsUnion"&gt;&lt;/a&gt; &lt;a href="https://github.com/type-challenges/type-challenges/./questions/01130-medium-replacekeys/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/80e38003eb6a163ff2032a3fac10b6ed50bb02f70277bed0f7863ea7d24d153a/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d313133302545332538332542425265706c6163654b6579732d643939303161" alt="1130・ReplaceKeys"&gt;&lt;/a&gt; &lt;a href="https://github.com/type-challenges/type-challenges/./questions/01367-medium-remove-index-signature/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/5b408f33a0365830a9e71ee7eb38d28922fd84fb5af060e3ce58e99ebc64875c/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d3133363725453325383325424252656d6f7665253230496e6465782532305369676e61747572652d643939303161" alt="1367・Remove Index Signature"&gt;&lt;/a&gt; &lt;a href="https://github.com/type-challenges/type-challenges/./questions/01978-medium-percentage-parser/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/ee5e30b65ab258b74fe59590f70dc3b32acf995420eb326a972bb618307e65a8/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d3139373825453325383325424250657263656e746167652532305061727365722d643939303161" alt="1978・Percentage Parser"&gt;&lt;/a&gt; &lt;a href="https://github.com/type-challenges/type-challenges/./questions/02070-medium-drop-char/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/e84206550bc23a1481ab72e1a5ead12c007bec35074d341b356da3f1378c7c23/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d3230373025453325383325424244726f70253230436861722d643939303161" alt="2070・Drop Char"&gt;&lt;/a&gt; &lt;a href="https://github.com/type-challenges/type-challenges/./questions/02257-medium-minusone/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/4e04486ad363fef286284462163a34afc35582e9fea5b6d22d1d217487c315bc/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d323235372545332538332542424d696e75734f6e652d643939303161" alt="2257・MinusOne"&gt;&lt;/a&gt; &lt;a href="https://github.com/type-challenges/type-challenges/./questions/02595-medium-pickbytype/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/8dc32b6c767b879ccbf802202c21ced6838223f5b7fb8204e57411e64f548162/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d323539352545332538332542425069636b4279547970652d643939303161" alt="2595・PickByType"&gt;&lt;/a&gt; &lt;a href="https://github.com/type-challenges/type-challenges/./questions/02688-medium-startswith/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/2eee5f124b66a450442055682e4df17e8aa405ee7fdb47bde626803b33520225/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d32363838254533253833254242537461727473576974682d643939303161" alt="2688・StartsWith"&gt;&lt;/a&gt; &lt;a href="https://github.com/type-challenges/type-challenges/./questions/02693-medium-endswith/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/ffb96bd1df29b3a99dab7d786c2bc9e7e787535883b834814f43f4098fe77450/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d32363933254533253833254242456e6473576974682d643939303161" alt="2693・EndsWith"&gt;&lt;/a&gt; &lt;a href="https://github.com/type-challenges/type-challenges/./questions/02757-medium-partialbykeys/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/33ac178f484a10bafde382c0d8d68fc13de47994ae1f14bb040dcbf74793b1c7/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d323735372545332538332542425061727469616c42794b6579732d643939303161" alt="2757・PartialByKeys"&gt;&lt;/a&gt; &lt;a href="https://github.com/type-challenges/type-challenges/./questions/02759-medium-requiredbykeys/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/b5746d46a222e30e878d0cf94dd036abb56402e50052e149119e1c8ede38464f/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d32373539254533253833254242526571756972656442794b6579732d643939303161" alt="2759・RequiredByKeys"&gt;&lt;/a&gt; &lt;a href="https://github.com/type-challenges/type-challenges/./questions/02793-medium-mutable/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/dbb8a88395fc2ba73624fb8087b1bab67d9fa7165e8bbe3914f13059d408666c/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d323739332545332538332542424d757461626c652d643939303161" alt="2793・Mutable"&gt;&lt;/a&gt; &lt;a href="https://github.com/type-challenges/type-challenges/./questions/02852-medium-omitbytype/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/63defee5c1616a50bfdf49171c44b9695df38cf1f5e0dce14761eb3e1c0b65e9/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d323835322545332538332542424f6d69744279547970652d643939303161" alt="2852・OmitByType"&gt;&lt;/a&gt; &lt;a href="https://github.com/type-challenges/type-challenges/./questions/02946-medium-objectentries/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/75cdd143a14c224cbe963e4d33c81418aae5b90a7caf1c12d03c238d76a75f8f/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d323934362545332538332542424f626a656374456e74726965732d643939303161" alt="2946・ObjectEntries"&gt;&lt;/a&gt; &lt;a href="https://github.com/type-challenges/type-challenges/./questions/03062-medium-shift/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/8503bfc64e4678cf037eb997bc98df1c7c30c8f3ce710324dd2b605696079c4f/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d3330363225453325383325424253686966742d643939303161" alt="3062・Shift"&gt;&lt;/a&gt; &lt;a href="https://github.com/type-challenges/type-challenges/./questions/03188-medium-tuple-to-nested-object/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/af12e4f2f3f2596a7b36a080493e13d085cb1a40ab3354919e5a2259e51661ef/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d333138382545332538332542425475706c65253230746f2532304e65737465642532304f626a6563742d643939303161" alt="3188・Tuple to Nested Object"&gt;&lt;/a&gt; &lt;a href="https://github.com/type-challenges/type-challenges/./questions/03192-medium-reverse/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/b5fc629258301e45c7c51035d7923017889f3ca6592c9ff238bb0093dbd3352d/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d33313932254533253833254242526576657273652d643939303161" alt="3192・Reverse"&gt;&lt;/a&gt; &lt;a href="https://github.com/type-challenges/type-challenges/./questions/03196-medium-flip-arguments/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/a3387a20d2ab91007ab018dc2aa6f229cba00346b8bc9865eefaf10aa1f6f6e6/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d33313936254533253833254242466c6970253230417267756d656e74732d643939303161" alt="3196・Flip Arguments"&gt;&lt;/a&gt; &lt;a href="https://github.com/type-challenges/type-challenges/./questions/03243-medium-flattendepth/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/d61b0b5025cb6f29e63310334074091acd63c389b73be9a521ea83f49a7d9476/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d33323433254533253833254242466c617474656e44657074682d643939303161" alt="3243・FlattenDepth"&gt;&lt;/a&gt; &lt;a href="https://github.com/type-challenges/type-challenges/./questions/03326-medium-bem-style-string/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/02a04d366569eb087cb57a7fa07e62ff01547947b5f35c9d84eaf1b1621b4450/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d3333323625453325383325424242454d2532307374796c65253230737472696e672d643939303161" alt="3326・BEM style string"&gt;&lt;/a&gt; &lt;a href="https://github.com/type-challenges/type-challenges/./questions/03376-medium-inordertraversal/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/9c97ff922603290566323c20dc8e2103744e61d095db3e0be47908e52f1e2eb6/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d33333736254533253833254242496e6f7264657254726176657273616c2d643939303161" alt="3376・InorderTraversal"&gt;&lt;/a&gt; &lt;a href="https://github.com/type-challenges/type-challenges/./questions/04179-medium-flip/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/fd298f58ca826f970f07d735c42b21a0d0cb10d2ec0ceceb6856af1645c1b525/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d34313739254533253833254242466c69702d643939303161" alt="4179・Flip"&gt;&lt;/a&gt; &lt;a href="https://github.com/type-challenges/type-challenges/./questions/04182-medium-fibonacci-sequence/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/d15f7372c1f66d48fcb7fc62f3f4a1d8fe934bf94c3afa5b486cddfe33091806/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d343138322545332538332542424669626f6e6163636925323053657175656e63652d643939303161" alt="4182・Fibonacci Sequence"&gt;&lt;/a&gt; &lt;a href="https://github.com/type-challenges/type-challenges/./questions/04260-medium-nomiwase/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/888c5a43fea9fcca69338edea6dfd5a2a3546fdaa45e551925195f59e6ad5794/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d34323630254533253833254242416c6c436f6d62696e6174696f6e732d643939303161" alt="4260・AllCombinations"&gt;&lt;/a&gt; &lt;a href="https://github.com/type-challenges/type-challenges/./questions/04425-medium-greater-than/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/f3f09bdd4419dc5af6abffebbcec654a2b9229aee21876d15ea4bbc3be10739c/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d34343235254533253833254242477265617465722532305468616e2d643939303161" alt="4425・Greater Than"&gt;&lt;/a&gt; &lt;a href="https://github.com/type-challenges/type-challenges/./questions/04471-medium-zip/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/8d8816c85885c858c43ea9987072b79e5ab5a4cfa0c6f11f0c86360e783b89bf/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d343437312545332538332542425a69702d643939303161" alt="4471・Zip"&gt;&lt;/a&gt; &lt;a href="https://github.com/type-challenges/type-challenges/./questions/04484-medium-istuple/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/aae3bf31b87ca03f5643f9ae66f7fcc93fcfa008f482db300ecb3d0e826e6eea/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d3434383425453325383325424249735475706c652d643939303161" alt="4484・IsTuple"&gt;&lt;/a&gt; &lt;a href="https://github.com/type-challenges/type-challenges/./questions/04499-medium-chunk/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/d930e8911729cf16e4c6ede5168237774661924e448acedba14702e40bc25c1c/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d343439392545332538332542424368756e6b2d643939303161" alt="4499・Chunk"&gt;&lt;/a&gt; &lt;a href="https://github.com/type-challenges/type-challenges/./questions/04518-medium-fill/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/eb28a6e703a3ee3c4326f94f3f598cd77a1e34fe9c172b2887049fd10f8ebdfa/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d3435313825453325383325424246696c6c2d643939303161" alt="4518・Fill"&gt;&lt;/a&gt; &lt;a href="https://github.com/type-challenges/type-challenges/./questions/04803-medium-trim-right/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/4322711ab44f46b0036a58e2a2c726d9ec8a6482863bfc93cde25b33d3f49205/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d343830332545332538332542425472696d25323052696768742d643939303161" alt="4803・Trim Right"&gt;&lt;/a&gt; &lt;a href="https://github.com/type-challenges/type-challenges/./questions/05117-medium-without/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/0219c277ba35d9a3a37d6e7f3846eba4fa519bc2535d6f19c9847b758cbb28f5/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d35313137254533253833254242576974686f75742d643939303161" alt="5117・Without"&gt;&lt;/a&gt; &lt;a href="https://github.com/type-challenges/type-challenges/./questions/05140-medium-trunc/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/227caf1add92cd065886d991b591ee59dc678e7d2cd5ba74722e0b16e47ea766/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d353134302545332538332542425472756e632d643939303161" alt="5140・Trunc"&gt;&lt;/a&gt; &lt;a href="https://github.com/type-challenges/type-challenges/./questions/05153-medium-indexof/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/d34f8dc270a725f8da7a7edb2cf8175b08c2b1f394665f2329ba35f2983f66fe/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d35313533254533253833254242496e6465784f662d643939303161" alt="5153・IndexOf"&gt;&lt;/a&gt; &lt;a href="https://github.com/type-challenges/type-challenges/./questions/05310-medium-join/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/345f4b71557da5d57343cb9fc2b357799a19a652e53cda258762874b9611ff30/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d353331302545332538332542424a6f696e2d643939303161" alt="5310・Join"&gt;&lt;/a&gt; &lt;a href="https://github.com/type-challenges/type-challenges/./questions/05317-medium-lastindexof/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/e5c0254fc9b84bbde8ea02d7375e1e8e501dcaace21ab1bc103348a6b3a542ac/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d353331372545332538332542424c617374496e6465784f662d643939303161" alt="5317・LastIndexOf"&gt;&lt;/a&gt; &lt;a href="https://github.com/type-challenges/type-challenges/./questions/05360-medium-unique/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/a3fc4b3fe5ee57e345328a3f90cf0b36ff496dfc5cf61d8bea513d31c2028afb/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d35333630254533253833254242556e697175652d643939303161" alt="5360・Unique"&gt;&lt;/a&gt; &lt;a href="https://github.com/type-challenges/type-challenges/./questions/05821-medium-maptypes/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/9f070a2446c6097b943fc7adfd7f6c580429db09109f041e1fa49863673907c1/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d353832312545332538332542424d617054797065732d643939303161" alt="5821・MapTypes"&gt;&lt;/a&gt; &lt;a href="https://github.com/type-challenges/type-challenges/./questions/07544-medium-construct-tuple/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/bf2526a88dfdf86e4fab2830c01aca0fd68b11841aafe8f01f809da9bc6d2437/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d37353434254533253833254242436f6e7374727563742532305475706c652d643939303161" alt="7544・Construct Tuple"&gt;&lt;/a&gt; &lt;a href="https://github.com/type-challenges/type-challenges/./questions/08640-medium-number-range/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/fc9a6e3496bd5618d2df25d29533b1fced5fc23847b912a74bd3e2b0fb83eaa9/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d383634302545332538332542424e756d62657225323052616e67652d643939303161" alt="8640・Number Range"&gt;&lt;/a&gt; &lt;a href="https://github.com/type-challenges/type-challenges/./questions/08767-medium-combination/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/10fc97eda4d6aa60327a4b794a445c61e9c7b5e89e172fab536c72317b284c09/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d38373637254533253833254242436f6d62696e6174696f6e2d643939303161" alt="8767・Combination"&gt;&lt;/a&gt; &lt;a href="https://github.com/type-challenges/type-challenges/./questions/08987-medium-subsequence/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/f62cf306b3ce3357e548e5adae5089e08e99e59041a3ff695ff4021da0c0fb2c/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d3839383725453325383325424253756273657175656e63652d643939303161" alt="8987・Subsequence"&gt;&lt;/a&gt; &lt;a href="https://github.com/type-challenges/type-challenges/./questions/09142-medium-checkrepeatedchars/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/6edd141426695023e450ccd4eab254d72ce36596f446c9d0a6a0c53afe8f7c4e/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d39313432254533253833254242436865636b526570656174656443686172732d643939303161" alt="9142・CheckRepeatedChars"&gt;&lt;/a&gt; &lt;a href="https://github.com/type-challenges/type-challenges/./questions/09286-medium-firstuniquecharindex/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/0321e5869fff9be339d68ba9fa385dfa36f12dce77585efb7260abf9eef02660/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d393238362545332538332542424669727374556e6971756543686172496e6465782d643939303161" alt="9286・FirstUniqueCharIndex"&gt;&lt;/a&gt; &lt;a href="https://github.com/type-challenges/type-challenges/./questions/09616-medium-parse-url-params/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/75f1b9208d1b0dfc6cdf9ec88e9c9955ef473d3879f58d3c0227183cfac81c48/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d39363136254533253833254242506172736525323055524c253230506172616d732d643939303161" alt="9616・Parse URL Params"&gt;&lt;/a&gt; &lt;a href="https://github.com/type-challenges/type-challenges/./questions/09896-medium-get-middle-element/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/49c5d49a15056a81367ed42e75da321fb8101675d578ac7da0f75e6d87b7487e/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d393839362545332538332542424765744d6964646c65456c656d656e742d643939303161" alt="9896・GetMiddleElement"&gt;&lt;/a&gt; &lt;a href="https://github.com/type-challenges/type-challenges/./questions/09898-medium-zhao-chu-mu-biao-shu-zu-zhong-zhi-chu-xian-guo-yi-ci-de-yuan-su/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/7d5405ea73f69ed5c11d5e793512da5d09e1de57d3b078e2250f7b64336b9658/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d393839382545332538332542424170706561722532306f6e6c792532306f6e63652d643939303161" alt="9898・Appear only once"&gt;&lt;/a&gt; &lt;a href="https://github.com/type-challenges/type-challenges/./questions/09989-medium-tong-ji-shu-zu-zhong-de-yuan-su-ge-shu/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/4a65597b3b1168315d3f92c87cc7b65ffa3afbbe016cdeba0bbebdae53be4200/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d39393839254533253833254242436f756e74253230456c656d656e742532304e756d626572253230546f2532304f626a6563742d643939303161" alt="9989・Count Element Number To Object"&gt;&lt;/a&gt; &lt;a href="https://github.com/type-challenges/type-challenges/./questions/10969-medium-integer/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/2704f7f1e838c6f9f250b57b913ae7e473793f1669af09fe524cf7a7cc895f22/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d3130393639254533253833254242496e74656765722d643939303161" alt="10969・Integer"&gt;&lt;/a&gt; &lt;a href="https://github.com/type-challenges/type-challenges/./questions/16259-medium-to-primitive/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/e10f86e5bab3062e6e2351a0e0392b64a47fdc8b0e2798bb62d0cd99f2cbf6b4/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d3136323539254533253833254242546f5072696d69746976652d643939303161" alt="16259・ToPrimitive"&gt;&lt;/a&gt; &lt;a href="https://github.com/type-challenges/type-challenges/./questions/17973-medium-deepmutable/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/97731bce386f90914211ef2db326e3df67f11cb85450b03902ec72c69c66aea2/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d3137393733254533253833254242446565704d757461626c652d643939303161" alt="17973・DeepMutable"&gt;&lt;/a&gt; &lt;a href="https://github.com/type-challenges/type-challenges/./questions/18142-medium-all/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/1c10348433764facb3adb53e00e4aabc452bf277e5ee7a76ce114462deee113c/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d3138313432254533253833254242416c6c2d643939303161" alt="18142・All"&gt;&lt;/a&gt; &lt;a href="https://github.com/type-challenges/type-challenges/./questions/18220-medium-filter/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/939f77ecf43d9c4b6a53c03903fb24230c9b4e47efae61be3da4f774dd2f6596/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d313832323025453325383325424246696c7465722d643939303161" alt="18220・Filter"&gt;&lt;/a&gt; &lt;a href="https://github.com/type-challenges/type-challenges/./questions/19749-medium-isequal/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/abab3657260d70361688646c137852587d47c878ceb6771f3ce9f23b6178e9b3/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d31393734392545332538332542424973457175616c2d643939303161" alt="19749・IsEqual"&gt;&lt;/a&gt; &lt;a href="https://github.com/type-challenges/type-challenges/./questions/21104-medium-findall/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/351fdce4765b15b8649aa342cf94df528c0a1f3ecf510daf15b4ef7fef6ef67c/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d323131303425453325383325424246696e64416c6c2d643939303161" alt="21104・FindAll"&gt;&lt;/a&gt; &lt;a href="https://github.com/type-challenges/type-challenges/./questions/21106-medium-zu-he-jian-lei-xing-combination-key-type/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/d8089168be1b1f8c189ab8c38124581dc584a0656be40807400d2cd8f79b5be5/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d3231313036254533253833254242436f6d62696e6174696f6e2532306b6579253230747970652d643939303161" alt="21106・Combination key type"&gt;&lt;/a&gt; &lt;a href="https://github.com/type-challenges/type-challenges/./questions/21220-medium-permutations-of-tuple/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/3ccad87140b6e85cad78030350db800106fc0d9fc8a4ebe9db5de657a30923cc/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d32313232302545332538332542425065726d75746174696f6e732532306f662532305475706c652d643939303161" alt="21220・Permutations of Tuple"&gt;&lt;/a&gt; &lt;a href="https://github.com/type-challenges/type-challenges/./questions/25170-medium-replace-first/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/2fffa915080253b38240ff39e0ba5a5f923265527c05c474e0b16987109e2144/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d32353137302545332538332542425265706c61636525323046697273742d643939303161" alt="25170・Replace First"&gt;&lt;/a&gt; &lt;a href="https://github.com/type-challenges/type-challenges/./questions/25270-medium-transpose/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/e8cb2edbc098ab54da5318f59b50923cf9f382fa4daa1614d6d989633ad2ca6d/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d32353237302545332538332542425472616e73706f73652d643939303161" alt="25270・Transpose"&gt;&lt;/a&gt; &lt;a href="https://github.com/type-challenges/type-challenges/./questions/26401-medium-json-schema-to-typescript/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/5befb5f6859ace68b8c59530f65d8ab9bf6842431836f38506d441122511d065/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d32363430312545332538332542424a534f4e253230536368656d61253230746f253230547970655363726970742d643939303161" alt="26401・JSON Schema to TypeScript"&gt;&lt;/a&gt; &lt;a href="https://github.com/type-challenges/type-challenges/./questions/27133-medium-square/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/36269f7150538bf2c83a6da2c3edf84f310cee21c08e93234d4720adb9f2f8c6/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d32373133332545332538332542425371756172652d643939303161" alt="27133・Square"&gt;&lt;/a&gt; &lt;a href="https://github.com/type-challenges/type-challenges/./questions/27152-medium-triangular-number/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/87bcfa511b8944ec186e0dea900ca316dcd9ca258a932c0521a77a2bf5efcde7/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d3237313532254533253833254242547269616e67756c61722532306e756d6265722d643939303161" alt="27152・Triangular number"&gt;&lt;/a&gt; &lt;a href="https://github.com/type-challenges/type-challenges/./questions/27862-medium-cartesianproduct/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/83043f8e8c38e814ef8bb5f505977c337d6ff8d5466b66ce4156e348977e3da9/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d323738363225453325383325424243617274657369616e50726f647563742d643939303161" alt="27862・CartesianProduct"&gt;&lt;/a&gt; &lt;a href="https://github.com/type-challenges/type-challenges/./questions/27932-medium-mergeall/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/d5be71388f3ee70e0270cfab5605edd458ed702f30bc8ea7473ea7bb9ba82d44/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d32373933322545332538332542424d65726765416c6c2d643939303161" alt="27932・MergeAll"&gt;&lt;/a&gt; &lt;a href="https://github.com/type-challenges/type-challenges/./questions/27958-medium-checkrepeatedtuple/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/a3f91591296877633514dd6514c844cba569ede211ecb9f17be0527c05228717/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d3237393538254533253833254242436865636b52657065617465645475706c652d643939303161" alt="27958・CheckRepeatedTuple"&gt;&lt;/a&gt; &lt;a href="https://github.com/type-challenges/type-challenges/./questions/28333-medium-public-type/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/7137f97ee7d7d621326cde5a4bbbdf78b1b552a533c1599451312f627b6a678f/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d32383333332545332538332542425075626c6963253230547970652d643939303161" alt="28333・Public Type"&gt;&lt;/a&gt; &lt;a href="https://github.com/type-challenges/type-challenges/./questions/29650-medium-extracttoobject/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/749ccf15dcd2b58aee849a593a00c01d16ed2c857efedf735a739298b4eca966/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d323936353025453325383325424245787472616374546f4f626a6563742d643939303161" alt="29650・ExtractToObject"&gt;&lt;/a&gt; &lt;a href="https://github.com/type-challenges/type-challenges/./questions/29785-medium-deep-omit/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/1bc803b865e55289857b42eb9ec47b9791895162dae55b5d48403187727a115d/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d3239373835254533253833254242446565702532304f6d69742d643939303161" alt="29785・Deep Omit"&gt;&lt;/a&gt; &lt;a href="https://github.com/type-challenges/type-challenges/./questions/30301-medium-isodd/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/6f4fc19c53be3dc38e89a5f2c838f617e956da90e918a61f4b064f598c05f600/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d333033303125453325383325424249734f64642d643939303161" alt="30301・IsOdd"&gt;&lt;/a&gt; &lt;a href="https://github.com/type-challenges/type-challenges/./questions/30430-medium-tower-of-hanoi/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/1a95d2d85ce084cdf113ff3a3afb0688e99dc33341b9ecc4978e9080c2470d99/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d3330343330254533253833254242546f7765722532306f6625323068616e6f692d643939303161" alt="30430・Tower of hanoi"&gt;&lt;/a&gt; &lt;a href="https://github.com/type-challenges/type-challenges/./questions/30958-medium-pascals-triangle/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/66bdeed30d80caa185d6c7456c41aea95ecd964a2e71e7a84464720de30e4da6/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d333039353825453325383325424250617363616c2773253230747269616e676c652d643939303161" alt="30958・Pascal's triangle"&gt;&lt;/a&gt; &lt;a href="https://github.com/type-challenges/type-challenges/./questions/30970-medium-shitariteraru/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/97d3d9612c9d0df8e6870d6b41e59df3c11d42a848c8bf779f502940e09995f9/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d333039373025453325383325424249734669786564537472696e674c69746572616c547970652d643939303161" alt="30970・IsFixedStringLiteralType"&gt;&lt;/a&gt; &lt;a href="https://github.com/type-challenges/type-challenges/./questions/34007-medium-compare-array-length/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/d60980be0f92b2662acf48c5c08410a72fa45f1cfda2b3c253c244065ff132b2/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d3334303037254533253833254242436f6d7061726525323041727261792532304c656e6774682d643939303161" alt="34007・Compare Array Length"&gt;&lt;/a&gt; &lt;a href="https://github.com/type-challenges/type-challenges/./questions/34857-medium-defined-partial-record/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/d7e1abb4397755b4487b043e218a0fe76955e5f7fabae1d19c29f5f37bff588c/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d3334383537254533253833254242446566696e65642532305061727469616c2532305265636f72642d643939303161" alt="34857・Defined Partial Record"&gt;&lt;/a&gt; &lt;a href="https://github.com/type-challenges/type-challenges/./questions/35045-medium-longest-common-prefix/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/10ffa5099cb35b72d1840c9271c12a2a0b70d0908b6226ddbf95778a5f2a8f45/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d33353034352545332538332542424c6f6e67657374253230436f6d6d6f6e2532305072656669782d643939303161" alt="35045・Longest Common Prefix"&gt;&lt;/a&gt; &lt;a href="https://github.com/type-challenges/type-challenges/./questions/35191-medium-trace/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/6777498ba85c45fb413edeedc33fd84824bd049eb11287a15c892521b37b19b8/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d333531393125453325383325424254726163652d643939303161" alt="35191・Trace"&gt;&lt;/a&gt; &lt;a href="https://github.com/type-challenges/type-challenges/./questions/35252-medium-isalphabet/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/f4870cf05fbcfd4a72e7c41d85728b10de76b6ab0e1e1b6994941e9b60ad97de/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d33353235322545332538332542424973416c7068616265742d643939303161" alt="35252・IsAlphabet"&gt;&lt;/a&gt; &lt;a href="https://github.com/type-challenges/type-challenges/./questions/35991-medium-myuppercase/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/971b65a15b95893f2e5cd849fd09251acf0deed042c973f7c3e512c3ac42d891/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d33353939312545332538332542424d795570706572636173652d643939303161" alt="35991・MyUppercase"&gt;&lt;/a&gt; &lt;br&gt;&lt;br&gt;&lt;a rel="noopener noreferrer nofollow" href="https://camo.githubusercontent.com/1966ddb20671281ed1692034ada9d703da6a76833841bd109c82cfb9320a34a8/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f686172642d35352d646533643337"&gt;&lt;img src="https://camo.githubusercontent.com/1966ddb20671281ed1692034ada9d703da6a76833841bd109c82cfb9320a34a8/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f686172642d35352d646533643337" alt="55"&gt;&lt;/a&gt;&lt;br&gt;&lt;a href="https://github.com/type-challenges/type-challenges/./questions/00006-hard-simple-vue/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/11c205500632987f2d5a8e821e0a7e2b8dc80c29207b5504b378419f074beb9f/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d3625453325383325424253696d706c652532305675652d646533643337" alt="6・Simple Vue"&gt;&lt;/a&gt; &lt;a href="https://github.com/type-challenges/type-challenges/./questions/00017-hard-currying-1/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/291c60e6728eb761f819eca0b275c39c37c20bd5b2f4885cbf802e541e72e396/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d31372545332538332542424375727279696e67253230312d646533643337" alt="17・Currying 1"&gt;&lt;/a&gt; &lt;a href="https://github.com/type-challenges/type-challenges/./questions/00055-hard-union-to-intersection/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/e34711b35e8bb219f384cb3ac8401e87123a093f681f2483870224e96730101a/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d3535254533253833254242556e696f6e253230746f253230496e74657273656374696f6e2d646533643337" alt="55・Union to Intersection"&gt;&lt;/a&gt; &lt;a href="https://github.com/type-challenges/type-challenges/./questions/00057-hard-get-required/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/8ca24e948c249fdba977744b2c7f4c3bc3a6a2396b88f785397adee516879c98/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d353725453325383325424247657425323052657175697265642d646533643337" alt="57・Get Required"&gt;&lt;/a&gt; &lt;a href="https://github.com/type-challenges/type-challenges/./questions/00059-hard-get-optional/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/e1ec70cccd26b483e4822810c39723c8f9b6cb2c76fbde7347fd68d156061142/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d35392545332538332542424765742532304f7074696f6e616c2d646533643337" alt="59・Get Optional"&gt;&lt;/a&gt; &lt;a href="https://github.com/type-challenges/type-challenges/./questions/00089-hard-required-keys/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/09f5c85e270866267174fee8aaf9e09c82bd4aaf6271ea78a792d24960d9ceb3/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d383925453325383325424252657175697265642532304b6579732d646533643337" alt="89・Required Keys"&gt;&lt;/a&gt; &lt;a href="https://github.com/type-challenges/type-challenges/./questions/00090-hard-optional-keys/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/f802327306992954f07d0e26abef3fed4fb9e0134ac0a9aafabb51ebf1ce44cf/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d39302545332538332542424f7074696f6e616c2532304b6579732d646533643337" alt="90・Optional Keys"&gt;&lt;/a&gt; &lt;a href="https://github.com/type-challenges/type-challenges/./questions/00112-hard-capitalizewords/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/6016b6f299472f07999016097747b9c93ca988013ed85da20223787d8869edd6/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d3131322545332538332542424361706974616c697a65253230576f7264732d646533643337" alt="112・Capitalize Words"&gt;&lt;/a&gt; &lt;a href="https://github.com/type-challenges/type-challenges/./questions/00114-hard-camelcase/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/62e9f39c4935dd012bf4c560b5c5ac82e2cce327eda966292197d7516610af86/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d31313425453325383325424243616d656c436173652d646533643337" alt="114・CamelCase"&gt;&lt;/a&gt; &lt;a href="https://github.com/type-challenges/type-challenges/./questions/00147-hard-c-printf-parser/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/abc2cb5f78efdfc1a741ca72a9dd30e8695a22cac0b8e0bb0904be2eac9dc0ef/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d313437254533253833254242432d2d7072696e74662532305061727365722d646533643337" alt="147・C-printf Parser"&gt;&lt;/a&gt; &lt;a href="https://github.com/type-challenges/type-challenges/./questions/00213-hard-vue-basic-props/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/fa2dfd2ae83073d83c0a04604b3727f75237624cfc9c0355ca11b4da8f787961/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d323133254533253833254242567565253230426173696325323050726f70732d646533643337" alt="213・Vue Basic Props"&gt;&lt;/a&gt; &lt;a href="https://github.com/type-challenges/type-challenges/./questions/00223-hard-isany/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/07ad316f7e03b4809017744f1b62c74961bd72f3ee63da5e970607cfcb860158/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d3232332545332538332542424973416e792d646533643337" alt="223・IsAny"&gt;&lt;/a&gt; &lt;a href="https://github.com/type-challenges/type-challenges/./questions/00270-hard-typed-get/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/02e8493a6b9864d406fd4fbe21e7f05b8ad57f876b30e2d7463f448c15cb825c/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d32373025453325383325424254797065642532304765742d646533643337" alt="270・Typed Get"&gt;&lt;/a&gt; &lt;a href="https://github.com/type-challenges/type-challenges/./questions/00300-hard-string-to-number/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/cf9d8a0e71f195d0a73c32393a4e59e253901f009848ed2f708f16ab6f6217f2/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d333030254533253833254242537472696e67253230746f2532304e756d6265722d646533643337" alt="300・String to Number"&gt;&lt;/a&gt; &lt;a href="https://github.com/type-challenges/type-challenges/./questions/00399-hard-tuple-filter/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/8488e3b502b85df9daa9365356afcd9e56b3e25c14800dcb114972936dc28edc/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d3339392545332538332542425475706c6525323046696c7465722d646533643337" alt="399・Tuple Filter"&gt;&lt;/a&gt; &lt;a href="https://github.com/type-challenges/type-challenges/./questions/00472-hard-tuple-to-enum-object/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/7159a4227a441b491dd25dd1ead7875dcde5eddb0da7c1f01ca15f3e8ea71ce5/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d3437322545332538332542425475706c65253230746f253230456e756d2532304f626a6563742d646533643337" alt="472・Tuple to Enum Object"&gt;&lt;/a&gt; &lt;a href="https://github.com/type-challenges/type-challenges/./questions/00545-hard-printf/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/22612c1a16a4da8f62159912c2b2ca533d5b7e42c6f5e5c935c525ad11f5a365/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d3534352545332538332542427072696e74662d646533643337" alt="545・printf"&gt;&lt;/a&gt; &lt;a href="https://github.com/type-challenges/type-challenges/./questions/00553-hard-deep-object-to-unique/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/0e442cf873c63a21f61fe8f4a3ed1361a84b09de0a24a6f625937e7316529b5b/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d353533254533253833254242446565702532306f626a656374253230746f253230756e697175652d646533643337" alt="553・Deep object to unique"&gt;&lt;/a&gt; &lt;a href="https://github.com/type-challenges/type-challenges/./questions/00651-hard-length-of-string-2/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/9d4361dec5c90675a0d975bb49f0f3c2ef0b1b8d23dfcc4930a746f7e8ad1fba/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d3635312545332538332542424c656e6774682532306f66253230537472696e67253230322d646533643337" alt="651・Length of String 2"&gt;&lt;/a&gt; &lt;a href="https://github.com/type-challenges/type-challenges/./questions/00730-hard-union-to-tuple/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/f8825b6275ff3692389fa7e85a0c0a75c3214f6750ab886f32b8a877ce9cb495/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d373330254533253833254242556e696f6e253230746f2532305475706c652d646533643337" alt="730・Union to Tuple"&gt;&lt;/a&gt; &lt;a href="https://github.com/type-challenges/type-challenges/./questions/00847-hard-string-join/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/f8eacd33da503f569275bb5956221e5e034be8eaa1464c17bc0898d940c9ef12/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d383437254533253833254242537472696e672532304a6f696e2d646533643337" alt="847・String Join"&gt;&lt;/a&gt; &lt;a href="https://github.com/type-challenges/type-challenges/./questions/00956-hard-deeppick/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/ae45dd5d193eae12637778d1b8077de6133e095f53d2b43c5e8b4be61ea4c043/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d393536254533253833254242446565705069636b2d646533643337" alt="956・DeepPick"&gt;&lt;/a&gt; &lt;a href="https://github.com/type-challenges/type-challenges/./questions/01290-hard-pinia/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/98d7983cead46b6e2752362c22df4c9f7f2662e427a06dfc8295d74984422be4/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d3132393025453325383325424250696e69612d646533643337" alt="1290・Pinia"&gt;&lt;/a&gt; &lt;a href="https://github.com/type-challenges/type-challenges/./questions/01383-hard-camelize/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/eda4cb01b58a4fc3986f005809c9fb8a276d8fb70aa52ad8fa352fa7decb6915/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d3133383325453325383325424243616d656c697a652d646533643337" alt="1383・Camelize"&gt;&lt;/a&gt; &lt;a href="https://github.com/type-challenges/type-challenges/./questions/02059-hard-drop-string/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/4707d40db5f4668fc3056ba895cbc508b70ca162fde0d9a235ef744139312a59/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d3230353925453325383325424244726f70253230537472696e672d646533643337" alt="2059・Drop String"&gt;&lt;/a&gt; &lt;a href="https://github.com/type-challenges/type-challenges/./questions/02822-hard-split/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/df1af9607965c50e51965443c37cc30346af6b7c992600e2a41778f16ff9beb5/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d3238323225453325383325424253706c69742d646533643337" alt="2822・Split"&gt;&lt;/a&gt; &lt;a href="https://github.com/type-challenges/type-challenges/./questions/02828-hard-classpublickeys/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/f9e726db1b5044a464442093dee05ceb3c56a5236260232b32e864751f57cbff/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d32383238254533253833254242436c6173735075626c69634b6579732d646533643337" alt="2828・ClassPublicKeys"&gt;&lt;/a&gt; &lt;a href="https://github.com/type-challenges/type-challenges/./questions/02857-hard-isrequiredkey/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/29cd9fc01f1dd96c358aa57f9931ae7f59b561a64a99f746972cf174c84d6d15/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d32383537254533253833254242497352657175697265644b65792d646533643337" alt="2857・IsRequiredKey"&gt;&lt;/a&gt; &lt;a href="https://github.com/type-challenges/type-challenges/./questions/02949-hard-objectfromentries/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/835e2bb2741b2b2fe6b57c997947a65ec8f1bf0e11d5f95ab1e5d84e4589e97d/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d323934392545332538332542424f626a65637446726f6d456e74726965732d646533643337" alt="2949・ObjectFromEntries"&gt;&lt;/a&gt; &lt;a href="https://github.com/type-challenges/type-challenges/./questions/04037-hard-ispalindrome/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/05e1c8cf07677c6f2dddd3f1a9d2ad63619c49d40d1bee4e1113ab26eb315085/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d34303337254533253833254242497350616c696e64726f6d652d646533643337" alt="4037・IsPalindrome"&gt;&lt;/a&gt; &lt;a href="https://github.com/type-challenges/type-challenges/./questions/05181-hard-mutable-keys/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/b1596d8dd9f07e68d9ca791a060d5bc6457d7b0086397a746a84d29621866a61/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d353138312545332538332542424d757461626c652532304b6579732d646533643337" alt="5181・Mutable Keys"&gt;&lt;/a&gt; &lt;a href="https://github.com/type-challenges/type-challenges/./questions/05423-hard-intersection/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/c18d0ea98303521e014c20573391c4124d49379956f412b03c1a75977cde8c18/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d35343233254533253833254242496e74657273656374696f6e2d646533643337" alt="5423・Intersection"&gt;&lt;/a&gt; &lt;a href="https://github.com/type-challenges/type-challenges/./questions/06141-hard-binary-to-decimal/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/65125663efc9042ca727a95a9b20606d367a4e6e494b25c21c316e29e257c036/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d3631343125453325383325424242696e617279253230746f253230446563696d616c2d646533643337" alt="6141・Binary to Decimal"&gt;&lt;/a&gt; &lt;a href="https://github.com/type-challenges/type-challenges/./questions/07258-hard-object-key-paths/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/7896e0b7c50833c974aa92a3a0c76b86f58e2e7dfc3cff9cf1d61b2c07875a24/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d373235382545332538332542424f626a6563742532304b657925323050617468732d646533643337" alt="7258・Object Key Paths"&gt;&lt;/a&gt; &lt;a href="https://github.com/type-challenges/type-challenges/./questions/08804-hard-two-sum/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/53fad4c5e7d38474fc536d866d2bb2d0bdc546f4cc1803eadce4f3f1cdc34f35/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d3838303425453325383325424254776f25323053756d2d646533643337" alt="8804・Two Sum"&gt;&lt;/a&gt; &lt;a href="https://github.com/type-challenges/type-challenges/./questions/09155-hard-validdate/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/1e84c8dd4a50fe429ad12f3c38ffeda97a85da4c599164cf4cf960f9cefe4e27/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d3931353525453325383325424256616c6964446174652d646533643337" alt="9155・ValidDate"&gt;&lt;/a&gt; &lt;a href="https://github.com/type-challenges/type-challenges/./questions/09160-hard-assign/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/804b51066cbbce19c83767c21e3c8e9c90b056dd346e0d09a2d33b8bf5e9b0a7/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d3931363025453325383325424241737369676e2d646533643337" alt="9160・Assign"&gt;&lt;/a&gt; &lt;a href="https://github.com/type-challenges/type-challenges/./questions/09384-hard-maximum/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/32c1059ee5a70d4e6bbc60f91a578f2a431021869407b0dc8e790e84fff62914/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d393338342545332538332542424d6178696d756d2d646533643337" alt="9384・Maximum"&gt;&lt;/a&gt; &lt;a href="https://github.com/type-challenges/type-challenges/./questions/09775-hard-capitalize-nest-object-keys/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/d252664edf765469592975eb9c99a11bc25babcf71df931f4094e9bdc8ab7df2/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d393737352545332538332542424361706974616c697a652532304e6573742532304f626a6563742532304b6579732d646533643337" alt="9775・Capitalize Nest Object Keys"&gt;&lt;/a&gt; &lt;a href="https://github.com/type-challenges/type-challenges/./questions/13580-hard-replace-union/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/931f50c176ea0c9e45bcd0fda71a10aad18d5584c9bf39b6739cf7b8ab0a192b/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d31333538302545332538332542425265706c616365253230556e696f6e2d646533643337" alt="13580・Replace Union"&gt;&lt;/a&gt; &lt;a href="https://github.com/type-challenges/type-challenges/./questions/14080-hard-fizzbuzz/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/33b7ced239d994ce3b788a41a450e3266302a59be4af68d075f7889d873f2ae1/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d313430383025453325383325424246697a7a42757a7a2d646533643337" alt="14080・FizzBuzz"&gt;&lt;/a&gt; &lt;a href="https://github.com/type-challenges/type-challenges/./questions/14188-hard-run-length-encoding/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/ed61fbdcb4ad5e8e6eb63d45234864ef3155b60bbac843d055de8284c733a343/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d313431383825453325383325424252756e2d2d6c656e677468253230656e636f64696e672d646533643337" alt="14188・Run-length encoding"&gt;&lt;/a&gt; &lt;a href="https://github.com/type-challenges/type-challenges/./questions/15260-hard-tree-path-array/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/11b03a67b7f1004b430acfcb8777b34a80d77e3339338592fb724bb42ce74bc0/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d3135323630254533253833254242547265652532307061746825323061727261792d646533643337" alt="15260・Tree path array"&gt;&lt;/a&gt; &lt;a href="https://github.com/type-challenges/type-challenges/./questions/19458-hard-snakecase/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/20dba8c816b5eb7282ecd0261170dec73632b2631489456836d82fc1a056c1cb/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d3139343538254533253833254242536e616b65436173652d646533643337" alt="19458・SnakeCase"&gt;&lt;/a&gt; &lt;a href="https://github.com/type-challenges/type-challenges/./questions/25747-hard-isnegativenumber/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/21c1cec3bcd45325d2dff61d073d3737c3d226e460dc5de93bfba3ddd7020143/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d323537343725453325383325424249734e656761746976654e756d6265722d646533643337" alt="25747・IsNegativeNumber"&gt;&lt;/a&gt; &lt;a href="https://github.com/type-challenges/type-challenges/./questions/28143-hard-optionalundefined/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/b5b3c9431c26aeb3f2f4584cb986039fabd8742e75fe045a94d14a3fa01ca6c1/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d32383134332545332538332542424f7074696f6e616c556e646566696e65642d646533643337" alt="28143・OptionalUndefined"&gt;&lt;/a&gt; &lt;a href="https://github.com/type-challenges/type-challenges/./questions/30178-hard-unique-items/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/ac72916b5a750b9a29653a81171fac23493819885a11071137ed44cdcd0ddae3/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d3330313738254533253833254242556e697175652532304974656d732d646533643337" alt="30178・Unique Items"&gt;&lt;/a&gt; &lt;a href="https://github.com/type-challenges/type-challenges/./questions/30575-hard-bitwisexor/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/93b214f6be8296bdac401ea267f1006f4ec987aa60f5b492cefb3f6201aa4fa1/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d333035373525453325383325424242697477697365584f522d646533643337" alt="30575・BitwiseXOR"&gt;&lt;/a&gt; &lt;a href="https://github.com/type-challenges/type-challenges/./questions/31797-hard-sudoku/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/773ac8cc5a753cc3c34b9d4eebdb40363e8eafb6afc05dfff6a14b00e3c849c3/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d33313739372545332538332542425375646f6b752d646533643337" alt="31797・Sudoku"&gt;&lt;/a&gt; &lt;a href="https://github.com/type-challenges/type-challenges/./questions/31824-hard-length-of-string-3/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/6edc9473962e1709e82b5c370eefc872b34458f50aacd4d50a705b4872a13005/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d33313832342545332538332542424c656e6774682532306f66253230537472696e67253230332d646533643337" alt="31824・Length of String 3"&gt;&lt;/a&gt; &lt;a href="https://github.com/type-challenges/type-challenges/./questions/32427-hard-unbox/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/ff9f832048e07e7fe6b8e55521cc9942746897b5596a732135ebf62e579bdf84/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d3332343237254533253833254242556e626f782d646533643337" alt="32427・Unbox"&gt;&lt;/a&gt; &lt;a href="https://github.com/type-challenges/type-challenges/./questions/32532-hard-binary-addition/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/88fb9d63f4877ecd2c8dbaacf20659c47e3b5f5bbfb3876631908ba27fb87648/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d333235333225453325383325424242696e6172792532304164646974696f6e2d646533643337" alt="32532・Binary Addition"&gt;&lt;/a&gt; &lt;a href="https://github.com/type-challenges/type-challenges/./questions/33763-hard-union-to-object-from-key/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/51dbcf10e24767050132a408b5845b16e51c5a6748ae7232c6d19e102068e9ba/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d3333373633254533253833254242556e696f6e253230746f2532304f626a65637425323066726f6d2532306b65792d646533643337" alt="33763・Union to Object from key"&gt;&lt;/a&gt; &lt;a href="https://github.com/type-challenges/type-challenges/./questions/34286-hard-take-elements/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/c0d47e8133de1b39708d2a3ddccd38367ee723976adcd510757385ecc5906b65/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d333432383625453325383325424254616b65253230456c656d656e74732d646533643337" alt="34286・Take Elements"&gt;&lt;/a&gt; &lt;a href="https://github.com/type-challenges/type-challenges/./questions/35314-hard-valid-sudoku/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/e4fc22abbd1a8f15f8cf0a1ceced69bc8ea45bbd1ab18177b61880ff5f41da7a/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d333533313425453325383325424256616c69642532305375646f6b752d646533643337" alt="35314・Valid Sudoku"&gt;&lt;/a&gt; &lt;br&gt;&lt;br&gt;&lt;a rel="noopener noreferrer nofollow" href="https://camo.githubusercontent.com/e2b907c404f95763e2588d44c6632aa1952c5ad853af426efdb61af094496c64/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f65787472656d652d31372d623131623864"&gt;&lt;img src="https://camo.githubusercontent.com/e2b907c404f95763e2588d44c6632aa1952c5ad853af426efdb61af094496c64/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f65787472656d652d31372d623131623864" alt="17"&gt;&lt;/a&gt;&lt;br&gt;&lt;a href="https://github.com/type-challenges/type-challenges/./questions/00005-extreme-readonly-keys/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/02010a018c7e30910ca455004ca2e919f08924b4077f07b9189d5cd48790c806/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d35254533253833254242476574253230526561646f6e6c792532304b6579732d623131623864" alt="5・Get Readonly Keys"&gt;&lt;/a&gt; &lt;a href="https://github.com/type-challenges/type-challenges/./questions/00151-extreme-query-string-parser/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/f78cb4c1d31807b3605cebb9b4c48dd8094c26326ec77bbf2f690725b2f4aaf5/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d3135312545332538332542425175657279253230537472696e672532305061727365722d623131623864" alt="151・Query String Parser"&gt;&lt;/a&gt; &lt;a href="https://github.com/type-challenges/type-challenges/./questions/00216-extreme-slice/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/dcc785bb21cf6fe5b8e62b8c90abd3151f8772901ffcbf873dc18dfb8d752954/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d323136254533253833254242536c6963652d623131623864" alt="216・Slice"&gt;&lt;/a&gt; &lt;a href="https://github.com/type-challenges/type-challenges/./questions/00274-extreme-integers-comparator/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/59c32890f5c7ce63eef658134f0334f477a551a3c2d4bb588bdbf3ccd40021fe/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d323734254533253833254242496e746567657273253230436f6d70617261746f722d623131623864" alt="274・Integers Comparator"&gt;&lt;/a&gt; &lt;a href="https://github.com/type-challenges/type-challenges/./questions/00462-extreme-currying-2/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/c8993228fa1cbf923f583dc0bfaa1d27f8a13869358103785767a968a8ba9567/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d3436322545332538332542424375727279696e67253230322d623131623864" alt="462・Currying 2"&gt;&lt;/a&gt; &lt;a href="https://github.com/type-challenges/type-challenges/./questions/00476-extreme-sum/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/0e24d07201087a6fc864577f5922802a991b6662b1cc301a45c15a05920cfca3/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d34373625453325383325424253756d2d623131623864" alt="476・Sum"&gt;&lt;/a&gt; &lt;a href="https://github.com/type-challenges/type-challenges/./questions/00517-extreme-multiply/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/039400e467d7fd3c290123cd1319ee34ff0861a3360f623e69f167dffbd47176/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d3531372545332538332542424d756c7469706c792d623131623864" alt="517・Multiply"&gt;&lt;/a&gt; &lt;a href="https://github.com/type-challenges/type-challenges/./questions/00697-extreme-tag/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/26c58dc6d60c2da29cdb6790a698c3b5a1b600dac87a322cfad1cabb6693ac5c/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d3639372545332538332542425461672d623131623864" alt="697・Tag"&gt;&lt;/a&gt; &lt;a href="https://github.com/type-challenges/type-challenges/./questions/00734-extreme-inclusive-range/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/d67f8033523c3b285d90ef2a162678a73cf5e0d396a0dc2883a8c862e190429c/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d373334254533253833254242496e636c757369766525323052616e67652d623131623864" alt="734・Inclusive Range"&gt;&lt;/a&gt; &lt;a href="https://github.com/type-challenges/type-challenges/./questions/00741-extreme-sort/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/4cf2ea2d08385dc813be638200fed8824283bbb6e932e214838fd315741d8262/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d373431254533253833254242536f72742d623131623864" alt="741・Sort"&gt;&lt;/a&gt; &lt;a href="https://github.com/type-challenges/type-challenges/./questions/00869-extreme-distributeunions/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/53221c2a0ac8721d77659d4522cf796e65732d531aa6f05484338ed09bec93c4/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d38363925453325383325424244697374726962757465556e696f6e732d623131623864" alt="869・DistributeUnions"&gt;&lt;/a&gt; &lt;a href="https://github.com/type-challenges/type-challenges/./questions/00925-extreme-assert-array-index/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/8f5d3a816f36cbc4336e2f529faae2fa5569c5939ee73349471499e4383e2e12/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d3932352545332538332542424173736572742532304172726179253230496e6465782d623131623864" alt="925・Assert Array Index"&gt;&lt;/a&gt; &lt;a href="https://github.com/type-challenges/type-challenges/./questions/06228-extreme-json-parser/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/445189c078e2d30b5f595baf97b30c22a4912f9ab50bb890d23e0aaabfa4081f/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d363232382545332538332542424a534f4e2532305061727365722d623131623864" alt="6228・JSON Parser"&gt;&lt;/a&gt; &lt;a href="https://github.com/type-challenges/type-challenges/./questions/07561-extreme-subtract/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/2124762240a8dc6b8cb97a70446f970ebd1675cde483ad9f45a19e79b701b309/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d3735363125453325383325424253756274726163742d623131623864" alt="7561・Subtract"&gt;&lt;/a&gt; &lt;a href="https://github.com/type-challenges/type-challenges/./questions/31447-extreme-countreversepairs/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/627e58dc446ac9ed16b617ee7febc0e86df35fbbd5031b6309d67f2b9c07d260/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d3331343437254533253833254242436f756e745265766572736550616972732d623131623864" alt="31447・CountReversePairs"&gt;&lt;/a&gt; &lt;a href="https://github.com/type-challenges/type-challenges/./questions/31997-extreme-parameter-intersection/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/1f0e02704a6ba171842f8fccfb3aecc331e67962fceee6fed8646ad8551cd600/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d3331393937254533253833254242506172616d65746572253230496e74657273656374696f6e2d623131623864" alt="31997・Parameter Intersection"&gt;&lt;/a&gt; &lt;a href="https://github.com/type-challenges/type-challenges/./questions/33345-extreme-dynamic-route/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/22607170d2c151be6e00ebafa74cdaf1e583cdc05ae2b53d9db6fdf9e2cc173e/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d333333343525453325383325424244796e616d6963253230526f7574652d623131623864" alt="33345・Dynamic Route"&gt;&lt;/a&gt; &lt;br&gt;&lt;/p&gt;

&lt;p&gt;By Tags&lt;br&gt;&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;&lt;tbody&gt;
&lt;br&gt;
&lt;tr&gt;
&lt;br&gt;
&lt;td&gt;&lt;a rel="noopener noreferrer nofollow" href="https://camo.githubusercontent.com/de263d3729eb4872face5c647f3057b64a23c5ebf6ab57f069bc05a8a791c220/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d2532334a534f4e2d393939"&gt;&lt;img src="https://camo.githubusercontent.com/de263d3729eb4872face5c647f3057b64a23c5ebf6ab57f069bc05a8a791c220/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d2532334a534f4e2d393939" alt="#JSON"&gt;&lt;/a&gt;&lt;/td&gt;
&lt;br&gt;
&lt;td&gt;
&lt;br&gt;
&lt;a href="https://github.com/type-challenges/type-challenges/./questions/26401-medium-json-schema-to-typescript/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/5befb5f6859ace68b8c59530f65d8ab9bf6842431836f38506d441122511d065/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d32363430312545332538332542424a534f4e253230536368656d61253230746f253230547970655363726970742d643939303161" alt="26401・JSON Schema to TypeScript"&gt;&lt;/a&gt; &lt;a href="https://github.com/type-challenges/type-challenges/./questions/06228-extreme-json-parser/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/445189c078e2d30b5f595baf97b30c22a4912f9ab50bb890d23e0aaabfa4081f/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d363232382545332538332542424a534f4e2532305061727365722d623131623864" alt="6228・JSON Parser"&gt;&lt;/a&gt; &lt;/td&gt;
&lt;br&gt;
&lt;/tr&gt;
&lt;br&gt;
&lt;tr&gt;
&lt;br&gt;
&lt;td&gt;&lt;a rel="noopener noreferrer nofollow" href="https://camo.githubusercontent.com/4507aa1690244d004062595eb128fa0454dcead30b94938c14317f77e1b7ccab/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d2532336170706c69636174696f6e2d393939"&gt;&lt;img src="https://camo.githubusercontent.com/4507aa1690244d004062595eb128fa0454dcead30b94938c14317f77e1b7ccab/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d2532336170706c69636174696f6e2d393939" alt="#application"&gt;&lt;/a&gt;&lt;/td&gt;
&lt;br&gt;
&lt;td&gt;
&lt;br&gt;
&lt;a href="https://github.com/type-challenges/type-challenges/./questions/00012-medium-chainable-options/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/aea4b9a471ae9f2c75f0da1814791f612e46272904011b03c043b6bf6de40c5e/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d3132254533253833254242436861696e61626c652532304f7074696f6e732d643939303161" alt="12・Chainable Options"&gt;&lt;/a&gt; &lt;a href="https://github.com/type-challenges/type-challenges/./questions/08767-medium-combination/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/10fc97eda4d6aa60327a4b794a445c61e9c7b5e89e172fab536c72317b284c09/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d38373637254533253833254242436f6d62696e6174696f6e2d643939303161" alt="8767・Combination"&gt;&lt;/a&gt; &lt;a href="https://github.com/type-challenges/type-challenges/./questions/00006-hard-simple-vue/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/11c205500632987f2d5a8e821e0a7e2b8dc80c29207b5504b378419f074beb9f/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d3625453325383325424253696d706c652532305675652d646533643337" alt="6・Simple Vue"&gt;&lt;/a&gt; &lt;a href="https://github.com/type-challenges/type-challenges/./questions/00213-hard-vue-basic-props/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/fa2dfd2ae83073d83c0a04604b3727f75237624cfc9c0355ca11b4da8f787961/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d323133254533253833254242567565253230426173696325323050726f70732d646533643337" alt="213・Vue Basic Props"&gt;&lt;/a&gt; &lt;a href="https://github.com/type-challenges/type-challenges/./questions/30178-hard-unique-items/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/ac72916b5a750b9a29653a81171fac23493819885a11071137ed44cdcd0ddae3/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d3330313738254533253833254242556e697175652532304974656d732d646533643337" alt="30178・Unique Items"&gt;&lt;/a&gt; &lt;/td&gt;
&lt;br&gt;
&lt;/tr&gt;
&lt;br&gt;
&lt;tr&gt;
&lt;br&gt;
&lt;td&gt;&lt;a rel="noopener noreferrer nofollow" href="https://camo.githubusercontent.com/acd6b9271b4750bf39727ecf6ff2f2b529eff6018859ed5d1892ad694924ac73/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d253233617267756d656e74732d393939"&gt;&lt;img src="https://camo.githubusercontent.com/acd6b9271b4750bf39727ecf6ff2f2b529eff6018859ed5d1892ad694924ac73/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d253233617267756d656e74732d393939" alt="#arguments"&gt;&lt;/a&gt;&lt;/td&gt;
&lt;br&gt;
&lt;td&gt;
&lt;br&gt;
&lt;a href="https://github.com/type-challenges/type-challenges/./questions/00191-medium-append-argument/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/b5280c1981b5da2422cda461c5adfb7cf63bc238957b9b51ec8bbe962aa9ef87/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d313931254533253833254242417070656e64253230417267756d656e742d643939303161" alt="191・Append Argument"&gt;&lt;/a&gt; &lt;a href="https://github.com/type-challenges/type-challenges/./questions/03196-medium-flip-arguments/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/a3387a20d2ab91007ab018dc2aa6f229cba00346b8bc9865eefaf10aa1f6f6e6/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d33313936254533253833254242466c6970253230417267756d656e74732d643939303161" alt="3196・Flip Arguments"&gt;&lt;/a&gt; &lt;/td&gt;
&lt;br&gt;
&lt;/tr&gt;
&lt;br&gt;
&lt;tr&gt;
&lt;br&gt;
&lt;td&gt;&lt;a rel="noopener noreferrer nofollow" href="https://camo.githubusercontent.com/94adeda257a125928ff63328d7cca3778bf5fba29857d4f2c5811bcd6a71befa/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d25323361727261792d393939"&gt;&lt;img src="https://camo.githubusercontent.com/94adeda257a125928ff63328d7cca3778bf5fba29857d4f2c5811bcd6a71befa/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d25323361727261792d393939" alt="#array"&gt;&lt;/a&gt;&lt;/td&gt;
&lt;br&gt;
&lt;td&gt;
&lt;br&gt;
&lt;a href="https://github.com/type-challenges/type-challenges/./questions/00014-easy-first/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/be13b2c83820d0277a75db97b25288775cedabd995d9deb9ac95602bd9268826/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d313425453325383325424246697273742532306f6625323041727261792d376161643063" alt="14・First of Array"&gt;&lt;/a&gt; &lt;a href="https://github.com/type-challenges/type-challenges/./questions/00533-easy-concat/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/f3d5afa6143f18c062ce750649155be904949a04e8b3b36bd2296aa76a02ea06/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d353333254533253833254242436f6e6361742d376161643063" alt="533・Concat"&gt;&lt;/a&gt; &lt;a href="https://github.com/type-challenges/type-challenges/./questions/00898-easy-includes/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/1fc1ad61f4739b83034268e1d06edd172016c082fd0e87ffcc605c08a1d9a89b/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d383938254533253833254242496e636c756465732d376161643063" alt="898・Includes"&gt;&lt;/a&gt; &lt;a href="https://github.com/type-challenges/type-challenges/./questions/03057-easy-push/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/c8b44fb5d8cb9928db8c375c14d5f9235d3a0792a07f3e1ef9d6c21c197b5fa5/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d33303537254533253833254242507573682d376161643063" alt="3057・Push"&gt;&lt;/a&gt; &lt;a href="https://github.com/type-challenges/type-challenges/./questions/03060-easy-unshift/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/df24253c70091cba7830aacd772ced86c5b2231bdecf56c10cb9b54a3f7ec50a/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d33303630254533253833254242556e73686966742d376161643063" alt="3060・Unshift"&gt;&lt;/a&gt; &lt;a href="https://github.com/type-challenges/type-challenges/./questions/00015-medium-last/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/1c8b9b0d0c3a942bfbcee84eb951589ef10badac16355d2a9a61f4cadf8c0803/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d31352545332538332542424c6173742532306f6625323041727261792d643939303161" alt="15・Last of Array"&gt;&lt;/a&gt; &lt;a href="https://github.com/type-challenges/type-challenges/./questions/00016-medium-pop/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/17a2698e2af5965bdad2f14843f116630957afc585225f738b5d09d683d21a73/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d3136254533253833254242506f702d643939303161" alt="16・Pop"&gt;&lt;/a&gt; &lt;a href="https://github.com/type-challenges/type-challenges/./questions/00020-medium-promise-all/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/0c813d6ca109d17ef474e45f40902463c168693adcdf0d395b945b50dcb5576c/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d323025453325383325424250726f6d6973652e616c6c2d643939303161" alt="20・Promise.all"&gt;&lt;/a&gt; &lt;a href="https://github.com/type-challenges/type-challenges/./questions/00459-medium-flatten/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/e6c829ffc0591d77d2156e97341446b33014b9c1f3d0923f8384fd65c8d6102e/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d343539254533253833254242466c617474656e2d643939303161" alt="459・Flatten"&gt;&lt;/a&gt; &lt;a href="https://github.com/type-challenges/type-challenges/./questions/00949-medium-anyof/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/ec5408aaaa684507be6a071e9a80c52a9696a83df114855f095055e77f67d5a5/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d393439254533253833254242416e794f662d643939303161" alt="949・AnyOf"&gt;&lt;/a&gt; &lt;a href="https://github.com/type-challenges/type-challenges/./questions/03062-medium-shift/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/8503bfc64e4678cf037eb997bc98df1c7c30c8f3ce710324dd2b605696079c4f/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d3330363225453325383325424253686966742d643939303161" alt="3062・Shift"&gt;&lt;/a&gt; &lt;a href="https://github.com/type-challenges/type-challenges/./questions/03243-medium-flattendepth/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/d61b0b5025cb6f29e63310334074091acd63c389b73be9a521ea83f49a7d9476/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d33323433254533253833254242466c617474656e44657074682d643939303161" alt="3243・FlattenDepth"&gt;&lt;/a&gt; &lt;a href="https://github.com/type-challenges/type-challenges/./questions/04425-medium-greater-than/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/f3f09bdd4419dc5af6abffebbcec654a2b9229aee21876d15ea4bbc3be10739c/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d34343235254533253833254242477265617465722532305468616e2d643939303161" alt="4425・Greater Than"&gt;&lt;/a&gt; &lt;a href="https://github.com/type-challenges/type-challenges/./questions/05117-medium-without/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/0219c277ba35d9a3a37d6e7f3846eba4fa519bc2535d6f19c9847b758cbb28f5/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d35313137254533253833254242576974686f75742d643939303161" alt="5117・Without"&gt;&lt;/a&gt; &lt;a href="https://github.com/type-challenges/type-challenges/./questions/05153-medium-indexof/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/d34f8dc270a725f8da7a7edb2cf8175b08c2b1f394665f2329ba35f2983f66fe/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d35313533254533253833254242496e6465784f662d643939303161" alt="5153・IndexOf"&gt;&lt;/a&gt; &lt;a href="https://github.com/type-challenges/type-challenges/./questions/05310-medium-join/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/345f4b71557da5d57343cb9fc2b357799a19a652e53cda258762874b9611ff30/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d353331302545332538332542424a6f696e2d643939303161" alt="5310・Join"&gt;&lt;/a&gt; &lt;a href="https://github.com/type-challenges/type-challenges/./questions/05317-medium-lastindexof/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/e5c0254fc9b84bbde8ea02d7375e1e8e501dcaace21ab1bc103348a6b3a542ac/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d353331372545332538332542424c617374496e6465784f662d643939303161" alt="5317・LastIndexOf"&gt;&lt;/a&gt; &lt;a href="https://github.com/type-challenges/type-challenges/./questions/05360-medium-unique/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/a3fc4b3fe5ee57e345328a3f90cf0b36ff496dfc5cf61d8bea513d31c2028afb/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d35333630254533253833254242556e697175652d643939303161" alt="5360・Unique"&gt;&lt;/a&gt; &lt;a href="https://github.com/type-challenges/type-challenges/./questions/08767-medium-combination/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/10fc97eda4d6aa60327a4b794a445c61e9c7b5e89e172fab536c72317b284c09/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d38373637254533253833254242436f6d62696e6174696f6e2d643939303161" alt="8767・Combination"&gt;&lt;/a&gt; &lt;a href="https://github.com/type-challenges/type-challenges/./questions/18142-medium-all/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/1c10348433764facb3adb53e00e4aabc452bf277e5ee7a76ce114462deee113c/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d3138313432254533253833254242416c6c2d643939303161" alt="18142・All"&gt;&lt;/a&gt; &lt;a href="https://github.com/type-challenges/type-challenges/./questions/18220-medium-filter/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/939f77ecf43d9c4b6a53c03903fb24230c9b4e47efae61be3da4f774dd2f6596/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d313832323025453325383325424246696c7465722d643939303161" alt="18220・Filter"&gt;&lt;/a&gt; &lt;a href="https://github.com/type-challenges/type-challenges/./questions/25270-medium-transpose/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/e8cb2edbc098ab54da5318f59b50923cf9f382fa4daa1614d6d989633ad2ca6d/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d32353237302545332538332542425472616e73706f73652d643939303161" alt="25270・Transpose"&gt;&lt;/a&gt; &lt;a href="https://github.com/type-challenges/type-challenges/./questions/27133-medium-square/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/36269f7150538bf2c83a6da2c3edf84f310cee21c08e93234d4720adb9f2f8c6/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d32373133332545332538332542425371756172652d643939303161" alt="27133・Square"&gt;&lt;/a&gt; &lt;a href="https://github.com/type-challenges/type-challenges/./questions/27152-medium-triangular-number/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/87bcfa511b8944ec186e0dea900ca316dcd9ca258a932c0521a77a2bf5efcde7/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d3237313532254533253833254242547269616e67756c61722532306e756d6265722d643939303161" alt="27152・Triangular number"&gt;&lt;/a&gt; &lt;a href="https://github.com/type-challenges/type-challenges/./questions/27932-medium-mergeall/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/d5be71388f3ee70e0270cfab5605edd458ed702f30bc8ea7473ea7bb9ba82d44/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d32373933322545332538332542424d65726765416c6c2d643939303161" alt="27932・MergeAll"&gt;&lt;/a&gt; &lt;a href="https://github.com/type-challenges/type-challenges/./questions/30430-medium-tower-of-hanoi/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/1a95d2d85ce084cdf113ff3a3afb0688e99dc33341b9ecc4978e9080c2470d99/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d3330343330254533253833254242546f7765722532306f6625323068616e6f692d643939303161" alt="30430・Tower of hanoi"&gt;&lt;/a&gt; &lt;a href="https://github.com/type-challenges/type-challenges/./questions/30958-medium-pascals-triangle/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/66bdeed30d80caa185d6c7456c41aea95ecd964a2e71e7a84464720de30e4da6/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d333039353825453325383325424250617363616c2773253230747269616e676c652d643939303161" alt="30958・Pascal's triangle"&gt;&lt;/a&gt; &lt;a href="https://github.com/type-challenges/type-challenges/./questions/34007-medium-compare-array-length/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/d60980be0f92b2662acf48c5c08410a72fa45f1cfda2b3c253c244065ff132b2/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d3334303037254533253833254242436f6d7061726525323041727261792532304c656e6774682d643939303161" alt="34007・Compare Array Length"&gt;&lt;/a&gt; &lt;a href="https://github.com/type-challenges/type-challenges/./questions/00017-hard-currying-1/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/291c60e6728eb761f819eca0b275c39c37c20bd5b2f4885cbf802e541e72e396/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d31372545332538332542424375727279696e67253230312d646533643337" alt="17・Currying 1"&gt;&lt;/a&gt; &lt;a href="https://github.com/type-challenges/type-challenges/./questions/02822-hard-split/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/df1af9607965c50e51965443c37cc30346af6b7c992600e2a41778f16ff9beb5/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d3238323225453325383325424253706c69742d646533643337" alt="2822・Split"&gt;&lt;/a&gt; &lt;a href="https://github.com/type-challenges/type-challenges/./questions/05423-hard-intersection/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/c18d0ea98303521e014c20573391c4124d49379956f412b03c1a75977cde8c18/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d35343233254533253833254242496e74657273656374696f6e2d646533643337" alt="5423・Intersection"&gt;&lt;/a&gt; &lt;a href="https://github.com/type-challenges/type-challenges/./questions/08804-hard-two-sum/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/53fad4c5e7d38474fc536d866d2bb2d0bdc546f4cc1803eadce4f3f1cdc34f35/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d3838303425453325383325424254776f25323053756d2d646533643337" alt="8804・Two Sum"&gt;&lt;/a&gt; &lt;a href="https://github.com/type-challenges/type-challenges/./questions/09160-hard-assign/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/804b51066cbbce19c83767c21e3c8e9c90b056dd346e0d09a2d33b8bf5e9b0a7/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d3931363025453325383325424241737369676e2d646533643337" alt="9160・Assign"&gt;&lt;/a&gt; &lt;a href="https://github.com/type-challenges/type-challenges/./questions/09384-hard-maximum/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/32c1059ee5a70d4e6bbc60f91a578f2a431021869407b0dc8e790e84fff62914/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d393338342545332538332542424d6178696d756d2d646533643337" alt="9384・Maximum"&gt;&lt;/a&gt; &lt;a href="https://github.com/type-challenges/type-challenges/./questions/09775-hard-capitalize-nest-object-keys/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/d252664edf765469592975eb9c99a11bc25babcf71df931f4094e9bdc8ab7df2/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d393737352545332538332542424361706974616c697a652532304e6573742532304f626a6563742532304b6579732d646533643337" alt="9775・Capitalize Nest Object Keys"&gt;&lt;/a&gt; &lt;a href="https://github.com/type-challenges/type-challenges/./questions/14080-hard-fizzbuzz/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/33b7ced239d994ce3b788a41a450e3266302a59be4af68d075f7889d873f2ae1/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d313430383025453325383325424246697a7a42757a7a2d646533643337" alt="14080・FizzBuzz"&gt;&lt;/a&gt; &lt;a href="https://github.com/type-challenges/type-challenges/./questions/31797-hard-sudoku/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/773ac8cc5a753cc3c34b9d4eebdb40363e8eafb6afc05dfff6a14b00e3c849c3/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d33313739372545332538332542425375646f6b752d646533643337" alt="31797・Sudoku"&gt;&lt;/a&gt; &lt;a href="https://github.com/type-challenges/type-challenges/./questions/32427-hard-unbox/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/ff9f832048e07e7fe6b8e55521cc9942746897b5596a732135ebf62e579bdf84/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d3332343237254533253833254242556e626f782d646533643337" alt="32427・Unbox"&gt;&lt;/a&gt; &lt;a href="https://github.com/type-challenges/type-challenges/./questions/32532-hard-binary-addition/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/88fb9d63f4877ecd2c8dbaacf20659c47e3b5f5bbfb3876631908ba27fb87648/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d333235333225453325383325424242696e6172792532304164646974696f6e2d646533643337" alt="32532・Binary Addition"&gt;&lt;/a&gt; &lt;a href="https://github.com/type-challenges/type-challenges/./questions/34286-hard-take-elements/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/c0d47e8133de1b39708d2a3ddccd38367ee723976adcd510757385ecc5906b65/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d333432383625453325383325424254616b65253230456c656d656e74732d646533643337" alt="34286・Take Elements"&gt;&lt;/a&gt; &lt;a href="https://github.com/type-challenges/type-challenges/./questions/35314-hard-valid-sudoku/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/e4fc22abbd1a8f15f8cf0a1ceced69bc8ea45bbd1ab18177b61880ff5f41da7a/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d333533313425453325383325424256616c69642532305375646f6b752d646533643337" alt="35314・Valid Sudoku"&gt;&lt;/a&gt; &lt;a href="https://github.com/type-challenges/type-challenges/./questions/00216-extreme-slice/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/dcc785bb21cf6fe5b8e62b8c90abd3151f8772901ffcbf873dc18dfb8d752954/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d323136254533253833254242536c6963652d623131623864" alt="216・Slice"&gt;&lt;/a&gt; &lt;a href="https://github.com/type-challenges/type-challenges/./questions/00734-extreme-inclusive-range/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/d67f8033523c3b285d90ef2a162678a73cf5e0d396a0dc2883a8c862e190429c/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d373334254533253833254242496e636c757369766525323052616e67652d623131623864" alt="734・Inclusive Range"&gt;&lt;/a&gt; &lt;a href="https://github.com/type-challenges/type-challenges/./questions/00741-extreme-sort/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/4cf2ea2d08385dc813be638200fed8824283bbb6e932e214838fd315741d8262/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d373431254533253833254242536f72742d623131623864" alt="741・Sort"&gt;&lt;/a&gt; &lt;a href="https://github.com/type-challenges/type-challenges/./questions/00925-extreme-assert-array-index/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/8f5d3a816f36cbc4336e2f529faae2fa5569c5939ee73349471499e4383e2e12/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d3932352545332538332542424173736572742532304172726179253230496e6465782d623131623864" alt="925・Assert Array Index"&gt;&lt;/a&gt; &lt;a href="https://github.com/type-challenges/type-challenges/./questions/31997-extreme-parameter-intersection/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/1f0e02704a6ba171842f8fccfb3aecc331e67962fceee6fed8646ad8551cd600/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d3331393937254533253833254242506172616d65746572253230496e74657273656374696f6e2d623131623864" alt="31997・Parameter Intersection"&gt;&lt;/a&gt; &lt;/td&gt;
&lt;br&gt;
&lt;/tr&gt;
&lt;br&gt;
&lt;tr&gt;
&lt;br&gt;
&lt;td&gt;&lt;a rel="noopener noreferrer nofollow" href="https://camo.githubusercontent.com/0790947c9661fa88d70853f988c2c22f1ca3effcbd4322a174bdc805fe7f8d1e/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d2532336275696c742d2d696e2d393939"&gt;&lt;img src="https://camo.githubusercontent.com/0790947c9661fa88d70853f988c2c22f1ca3effcbd4322a174bdc805fe7f8d1e/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d2532336275696c742d2d696e2d393939" alt="#built-in"&gt;&lt;/a&gt;&lt;/td&gt;
&lt;br&gt;
&lt;td&gt;
&lt;br&gt;
&lt;a href="https://github.com/type-challenges/type-challenges/./questions/00004-easy-pick/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/06d0211585b52905434f4e915f8d1a61c87b3c4cb14b229769424442873cc159/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d342545332538332542425069636b2d376161643063" alt="4・Pick"&gt;&lt;/a&gt; &lt;a href="https://github.com/type-challenges/type-challenges/./questions/00007-easy-readonly/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/84c51a27203cd8656e7912ebe93ac836abb21907ed2df8738c26ecc18f9dff81/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d37254533253833254242526561646f6e6c792d376161643063" alt="7・Readonly"&gt;&lt;/a&gt; &lt;a href="https://github.com/type-challenges/type-challenges/./questions/00043-easy-exclude/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/ba7e91e317c7798586097785f6fd386eae88932a6dd28dca14c84ab79ce246be/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d34332545332538332542424578636c7564652d376161643063" alt="43・Exclude"&gt;&lt;/a&gt; &lt;a href="https://github.com/type-challenges/type-challenges/./questions/00189-easy-awaited/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/bbef34543a44abf3666ba55e42426fc297fd5d6b30f75e854dcd14cd7f5ef2bf/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d313839254533253833254242417761697465642d376161643063" alt="189・Awaited"&gt;&lt;/a&gt; &lt;a href="https://github.com/type-challenges/type-challenges/./questions/03312-easy-parameters/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/08f4f79c8d4705b83ad15c4ed67dcd36ca5f5b7c8a177a756a1883011b655c87/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d33333132254533253833254242506172616d65746572732d376161643063" alt="3312・Parameters"&gt;&lt;/a&gt; &lt;a href="https://github.com/type-challenges/type-challenges/./questions/00002-medium-return-type/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/5c65927abde553215dcd6c2509e315c71caee596947155d9035c050ed5432115/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d3225453325383325424247657425323052657475726e253230547970652d643939303161" alt="2・Get Return Type"&gt;&lt;/a&gt; &lt;a href="https://github.com/type-challenges/type-challenges/./questions/00003-medium-omit/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/6b045a5c99e00480c82029e36f594071ef6b5578d3045eae9d430451f874f530/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d332545332538332542424f6d69742d643939303161" alt="3・Omit"&gt;&lt;/a&gt; &lt;/td&gt;
&lt;br&gt;
&lt;/tr&gt;
&lt;br&gt;
&lt;tr&gt;
&lt;br&gt;
&lt;td&gt;&lt;a rel="noopener noreferrer nofollow" href="https://camo.githubusercontent.com/fe49979a62361386daf43a29e0700ad83cd34308b99c1d07111c0828df9de252/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d2532336369662d393939"&gt;&lt;img src="https://camo.githubusercontent.com/fe49979a62361386daf43a29e0700ad83cd34308b99c1d07111c0828df9de252/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d2532336369662d393939" alt="#cif"&gt;&lt;/a&gt;&lt;/td&gt;
&lt;br&gt;
&lt;td&gt;
&lt;br&gt;
&lt;a href="https://github.com/type-challenges/type-challenges/./questions/30178-hard-unique-items/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/ac72916b5a750b9a29653a81171fac23493819885a11071137ed44cdcd0ddae3/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d3330313738254533253833254242556e697175652532304974656d732d646533643337" alt="30178・Unique Items"&gt;&lt;/a&gt; &lt;/td&gt;
&lt;br&gt;
&lt;/tr&gt;
&lt;br&gt;
&lt;tr&gt;
&lt;br&gt;
&lt;td&gt;&lt;a rel="noopener noreferrer nofollow" href="https://camo.githubusercontent.com/2fb9983badd058db0b6c80d0de00db34bf209c8b7679c54c04b0d608e82cd9d3/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d253233636f6e646974696f6e616c253230747970652d393939"&gt;&lt;img src="https://camo.githubusercontent.com/2fb9983badd058db0b6c80d0de00db34bf209c8b7679c54c04b0d608e82cd9d3/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d253233636f6e646974696f6e616c253230747970652d393939" alt="#conditional type"&gt;&lt;/a&gt;&lt;/td&gt;
&lt;br&gt;
&lt;td&gt;
&lt;br&gt;
&lt;a href="https://github.com/type-challenges/type-challenges/./questions/21220-medium-permutations-of-tuple/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/3ccad87140b6e85cad78030350db800106fc0d9fc8a4ebe9db5de657a30923cc/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d32313232302545332538332542425065726d75746174696f6e732532306f662532305475706c652d643939303161" alt="21220・Permutations of Tuple"&gt;&lt;/a&gt; &lt;/td&gt;
&lt;br&gt;
&lt;/tr&gt;
&lt;br&gt;
&lt;tr&gt;
&lt;br&gt;
&lt;td&gt;&lt;a rel="noopener noreferrer nofollow" href="https://camo.githubusercontent.com/754defc5220271f0b8d639038bf7de44ba0a5b1d10f02aef666ed767f7d93942/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d253233646565702d393939"&gt;&lt;img src="https://camo.githubusercontent.com/754defc5220271f0b8d639038bf7de44ba0a5b1d10f02aef666ed767f7d93942/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d253233646565702d393939" alt="#deep"&gt;&lt;/a&gt;&lt;/td&gt;
&lt;br&gt;
&lt;td&gt;
&lt;br&gt;
&lt;a href="https://github.com/type-challenges/type-challenges/./questions/00009-medium-deep-readonly/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/5f8a5a59fc2ca3e1a95fbe83e5967015270ef541c443c034d3012e87f58ae477/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d3925453325383325424244656570253230526561646f6e6c792d643939303161" alt="9・Deep Readonly"&gt;&lt;/a&gt; &lt;a href="https://github.com/type-challenges/type-challenges/./questions/17973-medium-deepmutable/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/97731bce386f90914211ef2db326e3df67f11cb85450b03902ec72c69c66aea2/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d3137393733254533253833254242446565704d757461626c652d643939303161" alt="17973・DeepMutable"&gt;&lt;/a&gt; &lt;a href="https://github.com/type-challenges/type-challenges/./questions/00553-hard-deep-object-to-unique/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/0e442cf873c63a21f61fe8f4a3ed1361a84b09de0a24a6f625937e7316529b5b/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d353533254533253833254242446565702532306f626a656374253230746f253230756e697175652d646533643337" alt="553・Deep object to unique"&gt;&lt;/a&gt; &lt;a href="https://github.com/type-challenges/type-challenges/./questions/00956-hard-deeppick/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/ae45dd5d193eae12637778d1b8077de6133e095f53d2b43c5e8b4be61ea4c043/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d393536254533253833254242446565705069636b2d646533643337" alt="956・DeepPick"&gt;&lt;/a&gt; &lt;/td&gt;
&lt;br&gt;
&lt;/tr&gt;
&lt;br&gt;
&lt;tr&gt;
&lt;br&gt;
&lt;td&gt;&lt;a rel="noopener noreferrer nofollow" href="https://camo.githubusercontent.com/e853cb750a60aedbc61838eba60e634e41355d7d8aecbfbb2799cc303dabca9e/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d25323366696c7465722d393939"&gt;&lt;img src="https://camo.githubusercontent.com/e853cb750a60aedbc61838eba60e634e41355d7d8aecbfbb2799cc303dabca9e/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d25323366696c7465722d393939" alt="#filter"&gt;&lt;/a&gt;&lt;/td&gt;
&lt;br&gt;
&lt;td&gt;
&lt;br&gt;
&lt;a href="https://github.com/type-challenges/type-challenges/./questions/18220-medium-filter/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/939f77ecf43d9c4b6a53c03903fb24230c9b4e47efae61be3da4f774dd2f6596/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d313832323025453325383325424246696c7465722d643939303161" alt="18220・Filter"&gt;&lt;/a&gt; &lt;/td&gt;
&lt;br&gt;
&lt;/tr&gt;
&lt;br&gt;
&lt;tr&gt;
&lt;br&gt;
&lt;td&gt;&lt;a rel="noopener noreferrer nofollow" href="https://camo.githubusercontent.com/bfa28d80854f0889c4f35d52ff2f08d63a2eb1b48af122fcf6b9d681c6fa9000/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d25323366756e6374696f6e2d393939"&gt;&lt;img src="https://camo.githubusercontent.com/bfa28d80854f0889c4f35d52ff2f08d63a2eb1b48af122fcf6b9d681c6fa9000/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d25323366756e6374696f6e2d393939" alt="#function"&gt;&lt;/a&gt;&lt;/td&gt;
&lt;br&gt;
&lt;td&gt;
&lt;br&gt;
&lt;a href="https://github.com/type-challenges/type-challenges/./questions/32427-hard-unbox/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/ff9f832048e07e7fe6b8e55521cc9942746897b5596a732135ebf62e579bdf84/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d3332343237254533253833254242556e626f782d646533643337" alt="32427・Unbox"&gt;&lt;/a&gt; &lt;/td&gt;
&lt;br&gt;
&lt;/tr&gt;
&lt;br&gt;
&lt;tr&gt;
&lt;br&gt;
&lt;td&gt;&lt;a rel="noopener noreferrer nofollow" href="https://camo.githubusercontent.com/f758ca189ef57408ce002ed306efb481e0ffbd4631dd750ddb2a5323cfc64bee/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d25323367616d652d393939"&gt;&lt;img src="https://camo.githubusercontent.com/f758ca189ef57408ce002ed306efb481e0ffbd4631dd750ddb2a5323cfc64bee/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d25323367616d652d393939" alt="#game"&gt;&lt;/a&gt;&lt;/td&gt;
&lt;br&gt;
&lt;td&gt;
&lt;br&gt;
&lt;a href="https://github.com/type-challenges/type-challenges/./questions/31797-hard-sudoku/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/773ac8cc5a753cc3c34b9d4eebdb40363e8eafb6afc05dfff6a14b00e3c849c3/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d33313739372545332538332542425375646f6b752d646533643337" alt="31797・Sudoku"&gt;&lt;/a&gt; &lt;a href="https://github.com/type-challenges/type-challenges/./questions/35314-hard-valid-sudoku/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/e4fc22abbd1a8f15f8cf0a1ceced69bc8ea45bbd1ab18177b61880ff5f41da7a/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d333533313425453325383325424256616c69642532305375646f6b752d646533643337" alt="35314・Valid Sudoku"&gt;&lt;/a&gt; &lt;/td&gt;
&lt;br&gt;
&lt;/tr&gt;
&lt;br&gt;
&lt;tr&gt;
&lt;br&gt;
&lt;td&gt;&lt;a rel="noopener noreferrer nofollow" href="https://camo.githubusercontent.com/84f7d4028bfa857a0a78bd8b6d8a7d8c2bf9c3720f58cf92169b38ee1707d66c/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d253233696e6665722d393939"&gt;&lt;img src="https://camo.githubusercontent.com/84f7d4028bfa857a0a78bd8b6d8a7d8c2bf9c3720f58cf92169b38ee1707d66c/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d253233696e6665722d393939" alt="#infer"&gt;&lt;/a&gt;&lt;/td&gt;
&lt;br&gt;
&lt;td&gt;
&lt;br&gt;
&lt;a href="https://github.com/type-challenges/type-challenges/./questions/03312-easy-parameters/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/08f4f79c8d4705b83ad15c4ed67dcd36ca5f5b7c8a177a756a1883011b655c87/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d33333132254533253833254242506172616d65746572732d376161643063" alt="3312・Parameters"&gt;&lt;/a&gt; &lt;a href="https://github.com/type-challenges/type-challenges/./questions/00002-medium-return-type/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/5c65927abde553215dcd6c2509e315c71caee596947155d9035c050ed5432115/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d3225453325383325424247657425323052657475726e253230547970652d643939303161" alt="2・Get Return Type"&gt;&lt;/a&gt; &lt;a href="https://github.com/type-challenges/type-challenges/./questions/00010-medium-tuple-to-union/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/49a65bc299035aa497ee2bacabafb5d229e7c7dd36a89ef03f062589a4660187/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d31302545332538332542425475706c65253230746f253230556e696f6e2d643939303161" alt="10・Tuple to Union"&gt;&lt;/a&gt; &lt;a href="https://github.com/type-challenges/type-challenges/./questions/02070-medium-drop-char/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/e84206550bc23a1481ab72e1a5ead12c007bec35074d341b356da3f1378c7c23/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d3230373025453325383325424244726f70253230436861722d643939303161" alt="2070・Drop Char"&gt;&lt;/a&gt; &lt;a href="https://github.com/type-challenges/type-challenges/./questions/04260-medium-nomiwase/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/888c5a43fea9fcca69338edea6dfd5a2a3546fdaa45e551925195f59e6ad5794/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d34323630254533253833254242416c6c436f6d62696e6174696f6e732d643939303161" alt="4260・AllCombinations"&gt;&lt;/a&gt; &lt;a href="https://github.com/type-challenges/type-challenges/./questions/09616-medium-parse-url-params/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/75f1b9208d1b0dfc6cdf9ec88e9c9955ef473d3879f58d3c0227183cfac81c48/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d39363136254533253833254242506172736525323055524c253230506172616d732d643939303161" alt="9616・Parse URL Params"&gt;&lt;/a&gt; &lt;a href="https://github.com/type-challenges/type-challenges/./questions/00055-hard-union-to-intersection/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/e34711b35e8bb219f384cb3ac8401e87123a093f681f2483870224e96730101a/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d3535254533253833254242556e696f6e253230746f253230496e74657273656374696f6e2d646533643337" alt="55・Union to Intersection"&gt;&lt;/a&gt; &lt;a href="https://github.com/type-challenges/type-challenges/./questions/00057-hard-get-required/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/8ca24e948c249fdba977744b2c7f4c3bc3a6a2396b88f785397adee516879c98/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d353725453325383325424247657425323052657175697265642d646533643337" alt="57・Get Required"&gt;&lt;/a&gt; &lt;a href="https://github.com/type-challenges/type-challenges/./questions/00059-hard-get-optional/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/e1ec70cccd26b483e4822810c39723c8f9b6cb2c76fbde7347fd68d156061142/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d35392545332538332542424765742532304f7074696f6e616c2d646533643337" alt="59・Get Optional"&gt;&lt;/a&gt; &lt;a href="https://github.com/type-challenges/type-challenges/./questions/00399-hard-tuple-filter/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/8488e3b502b85df9daa9365356afcd9e56b3e25c14800dcb114972936dc28edc/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d3339392545332538332542425475706c6525323046696c7465722d646533643337" alt="399・Tuple Filter"&gt;&lt;/a&gt; &lt;a href="https://github.com/type-challenges/type-challenges/./questions/00730-hard-union-to-tuple/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/f8825b6275ff3692389fa7e85a0c0a75c3214f6750ab886f32b8a877ce9cb495/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d373330254533253833254242556e696f6e253230746f2532305475706c652d646533643337" alt="730・Union to Tuple"&gt;&lt;/a&gt; &lt;a href="https://github.com/type-challenges/type-challenges/./questions/02059-hard-drop-string/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/4707d40db5f4668fc3056ba895cbc508b70ca162fde0d9a235ef744139312a59/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d3230353925453325383325424244726f70253230537472696e672d646533643337" alt="2059・Drop String"&gt;&lt;/a&gt; &lt;a href="https://github.com/type-challenges/type-challenges/./questions/14080-hard-fizzbuzz/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/33b7ced239d994ce3b788a41a450e3266302a59be4af68d075f7889d873f2ae1/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d313430383025453325383325424246697a7a42757a7a2d646533643337" alt="14080・FizzBuzz"&gt;&lt;/a&gt; &lt;a href="https://github.com/type-challenges/type-challenges/./questions/00734-extreme-inclusive-range/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/d67f8033523c3b285d90ef2a162678a73cf5e0d396a0dc2883a8c862e190429c/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d373334254533253833254242496e636c757369766525323052616e67652d623131623864" alt="734・Inclusive Range"&gt;&lt;/a&gt; &lt;a href="https://github.com/type-challenges/type-challenges/./questions/00741-extreme-sort/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/4cf2ea2d08385dc813be638200fed8824283bbb6e932e214838fd315741d8262/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d373431254533253833254242536f72742d623131623864" alt="741・Sort"&gt;&lt;/a&gt; &lt;/td&gt;
&lt;br&gt;
&lt;/tr&gt;
&lt;br&gt;
&lt;tr&gt;
&lt;br&gt;
&lt;td&gt;&lt;a rel="noopener noreferrer nofollow" href="https://camo.githubusercontent.com/f8a587eca59b4844a3f0f56ff7b4c8dd0367741c567653aed75d664f4c551b2e/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d253233696e74657273656374696f6e2d393939"&gt;&lt;img src="https://camo.githubusercontent.com/f8a587eca59b4844a3f0f56ff7b4c8dd0367741c567653aed75d664f4c551b2e/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d253233696e74657273656374696f6e2d393939" alt="#intersection"&gt;&lt;/a&gt;&lt;/td&gt;
&lt;br&gt;
&lt;td&gt;
&lt;br&gt;
&lt;a href="https://github.com/type-challenges/type-challenges/./questions/31997-extreme-parameter-intersection/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/1f0e02704a6ba171842f8fccfb3aecc331e67962fceee6fed8646ad8551cd600/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d3331393937254533253833254242506172616d65746572253230496e74657273656374696f6e2d623131623864" alt="31997・Parameter Intersection"&gt;&lt;/a&gt; &lt;/td&gt;
&lt;br&gt;
&lt;/tr&gt;
&lt;br&gt;
&lt;tr&gt;
&lt;br&gt;
&lt;td&gt;&lt;a rel="noopener noreferrer nofollow" href="https://camo.githubusercontent.com/20c332bfe2a7198b30c49a05c0936f6683d7e29d15b490832e7f5eb3b25f1603/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d2532336d61702d393939"&gt;&lt;img src="https://camo.githubusercontent.com/20c332bfe2a7198b30c49a05c0936f6683d7e29d15b490832e7f5eb3b25f1603/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d2532336d61702d393939" alt="#map"&gt;&lt;/a&gt;&lt;/td&gt;
&lt;br&gt;
&lt;td&gt;
&lt;br&gt;
&lt;a href="https://github.com/type-challenges/type-challenges/./questions/00062-medium-type-lookup/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/23682c391a565041676ad66a5366f0977654629e70a752712502aa4838b93263/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d3632254533253833254242547970652532304c6f6f6b75702d643939303161" alt="62・Type Lookup"&gt;&lt;/a&gt; &lt;a href="https://github.com/type-challenges/type-challenges/./questions/05821-medium-maptypes/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/9f070a2446c6097b943fc7adfd7f6c580429db09109f041e1fa49863673907c1/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d353832312545332538332542424d617054797065732d643939303161" alt="5821・MapTypes"&gt;&lt;/a&gt; &lt;/td&gt;
&lt;br&gt;
&lt;/tr&gt;
&lt;br&gt;
&lt;tr&gt;
&lt;br&gt;
&lt;td&gt;&lt;a rel="noopener noreferrer nofollow" href="https://camo.githubusercontent.com/279970f9f579fe0f323048f7c8c9a772a62d3f10d07b10f9a84471cbffbbf020/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d2532336d6174682d393939"&gt;&lt;img src="https://camo.githubusercontent.com/279970f9f579fe0f323048f7c8c9a772a62d3f10d07b10f9a84471cbffbbf020/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d2532336d6174682d393939" alt="#math"&gt;&lt;/a&gt;&lt;/td&gt;
&lt;br&gt;
&lt;td&gt;
&lt;br&gt;
&lt;a href="https://github.com/type-challenges/type-challenges/./questions/00529-medium-absolute/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/3d9badff828ae75c1c5159d33cf82985d01125177245d0ac19e32d76072daac0/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d3532392545332538332542424162736f6c7574652d643939303161" alt="529・Absolute"&gt;&lt;/a&gt; &lt;a href="https://github.com/type-challenges/type-challenges/./questions/02257-medium-minusone/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/4e04486ad363fef286284462163a34afc35582e9fea5b6d22d1d217487c315bc/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d323235372545332538332542424d696e75734f6e652d643939303161" alt="2257・MinusOne"&gt;&lt;/a&gt; &lt;a href="https://github.com/type-challenges/type-challenges/./questions/25270-medium-transpose/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/e8cb2edbc098ab54da5318f59b50923cf9f382fa4daa1614d6d989633ad2ca6d/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d32353237302545332538332542425472616e73706f73652d643939303161" alt="25270・Transpose"&gt;&lt;/a&gt; &lt;a href="https://github.com/type-challenges/type-challenges/./questions/27133-medium-square/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/36269f7150538bf2c83a6da2c3edf84f310cee21c08e93234d4720adb9f2f8c6/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d32373133332545332538332542425371756172652d643939303161" alt="27133・Square"&gt;&lt;/a&gt; &lt;a href="https://github.com/type-challenges/type-challenges/./questions/27152-medium-triangular-number/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/87bcfa511b8944ec186e0dea900ca316dcd9ca258a932c0521a77a2bf5efcde7/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d3237313532254533253833254242547269616e67756c61722532306e756d6265722d643939303161" alt="27152・Triangular number"&gt;&lt;/a&gt; &lt;a href="https://github.com/type-challenges/type-challenges/./questions/30958-medium-pascals-triangle/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/66bdeed30d80caa185d6c7456c41aea95ecd964a2e71e7a84464720de30e4da6/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d333039353825453325383325424250617363616c2773253230747269616e676c652d643939303161" alt="30958・Pascal's triangle"&gt;&lt;/a&gt; &lt;a href="https://github.com/type-challenges/type-challenges/./questions/06141-hard-binary-to-decimal/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/65125663efc9042ca727a95a9b20606d367a4e6e494b25c21c316e29e257c036/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d3631343125453325383325424242696e617279253230746f253230446563696d616c2d646533643337" alt="6141・Binary to Decimal"&gt;&lt;/a&gt; &lt;a href="https://github.com/type-challenges/type-challenges/./questions/08804-hard-two-sum/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/53fad4c5e7d38474fc536d866d2bb2d0bdc546f4cc1803eadce4f3f1cdc34f35/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d3838303425453325383325424254776f25323053756d2d646533643337" alt="8804・Two Sum"&gt;&lt;/a&gt; &lt;a href="https://github.com/type-challenges/type-challenges/./questions/14080-hard-fizzbuzz/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/33b7ced239d994ce3b788a41a450e3266302a59be4af68d075f7889d873f2ae1/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d313430383025453325383325424246697a7a42757a7a2d646533643337" alt="14080・FizzBuzz"&gt;&lt;/a&gt; &lt;a href="https://github.com/type-challenges/type-challenges/./questions/35314-hard-valid-sudoku/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/e4fc22abbd1a8f15f8cf0a1ceced69bc8ea45bbd1ab18177b61880ff5f41da7a/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d333533313425453325383325424256616c69642532305375646f6b752d646533643337" alt="35314・Valid Sudoku"&gt;&lt;/a&gt; &lt;a href="https://github.com/type-challenges/type-challenges/./questions/00274-extreme-integers-comparator/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/59c32890f5c7ce63eef658134f0334f477a551a3c2d4bb588bdbf3ccd40021fe/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d323734254533253833254242496e746567657273253230436f6d70617261746f722d623131623864" alt="274・Integers Comparator"&gt;&lt;/a&gt; &lt;a href="https://github.com/type-challenges/type-challenges/./questions/00476-extreme-sum/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/0e24d07201087a6fc864577f5922802a991b6662b1cc301a45c15a05920cfca3/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d34373625453325383325424253756d2d623131623864" alt="476・Sum"&gt;&lt;/a&gt; &lt;a href="https://github.com/type-challenges/type-challenges/./questions/00517-extreme-multiply/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/039400e467d7fd3c290123cd1319ee34ff0861a3360f623e69f167dffbd47176/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d3531372545332538332542424d756c7469706c792d623131623864" alt="517・Multiply"&gt;&lt;/a&gt; &lt;/td&gt;
&lt;br&gt;
&lt;/tr&gt;
&lt;br&gt;
&lt;tr&gt;
&lt;br&gt;
&lt;td&gt;&lt;a rel="noopener noreferrer nofollow" href="https://camo.githubusercontent.com/88553f2483200a300c05a85b6d99f114a52ac220136f38c7799409c3fe342de5/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d2532336e756d6265722d393939"&gt;&lt;img src="https://camo.githubusercontent.com/88553f2483200a300c05a85b6d99f114a52ac220136f38c7799409c3fe342de5/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d2532336e756d6265722d393939" alt="#number"&gt;&lt;/a&gt;&lt;/td&gt;
&lt;br&gt;
&lt;td&gt;
&lt;br&gt;
&lt;a href="https://github.com/type-challenges/type-challenges/./questions/25747-hard-isnegativenumber/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/21c1cec3bcd45325d2dff61d073d3737c3d226e460dc5de93bfba3ddd7020143/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d323537343725453325383325424249734e656761746976654e756d6265722d646533643337" alt="25747・IsNegativeNumber"&gt;&lt;/a&gt; &lt;/td&gt;
&lt;br&gt;
&lt;/tr&gt;
&lt;br&gt;
&lt;tr&gt;
&lt;br&gt;
&lt;td&gt;&lt;a rel="noopener noreferrer nofollow" href="https://camo.githubusercontent.com/16da684778d1307a2bc171f4d8f129902a204688c893b8f1f6eba987313c9f58/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d2532336f626a6563742d393939"&gt;&lt;img src="https://camo.githubusercontent.com/16da684778d1307a2bc171f4d8f129902a204688c893b8f1f6eba987313c9f58/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d2532336f626a6563742d393939" alt="#object"&gt;&lt;/a&gt;&lt;/td&gt;
&lt;br&gt;
&lt;td&gt;
&lt;br&gt;
&lt;a href="https://github.com/type-challenges/type-challenges/./questions/00599-medium-merge/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/80ac0910efa4965ae92d733a5eb961769be84bd936083e0ea8be1a8dea2f3e36/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d3539392545332538332542424d657267652d643939303161" alt="599・Merge"&gt;&lt;/a&gt; &lt;a href="https://github.com/type-challenges/type-challenges/./questions/00645-medium-diff/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/5b0fa66b1fe21775c2367877317117481c00a953808ac1bae899e0de300e9c10/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d363435254533253833254242446966662d643939303161" alt="645・Diff"&gt;&lt;/a&gt; &lt;a href="https://github.com/type-challenges/type-challenges/./questions/02595-medium-pickbytype/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/8dc32b6c767b879ccbf802202c21ced6838223f5b7fb8204e57411e64f548162/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d323539352545332538332542425069636b4279547970652d643939303161" alt="2595・PickByType"&gt;&lt;/a&gt; &lt;a href="https://github.com/type-challenges/type-challenges/./questions/02757-medium-partialbykeys/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/33ac178f484a10bafde382c0d8d68fc13de47994ae1f14bb040dcbf74793b1c7/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d323735372545332538332542425061727469616c42794b6579732d643939303161" alt="2757・PartialByKeys"&gt;&lt;/a&gt; &lt;a href="https://github.com/type-challenges/type-challenges/./questions/02759-medium-requiredbykeys/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/b5746d46a222e30e878d0cf94dd036abb56402e50052e149119e1c8ede38464f/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d32373539254533253833254242526571756972656442794b6579732d643939303161" alt="2759・RequiredByKeys"&gt;&lt;/a&gt; &lt;a href="https://github.com/type-challenges/type-challenges/./questions/02852-medium-omitbytype/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/63defee5c1616a50bfdf49171c44b9695df38cf1f5e0dce14761eb3e1c0b65e9/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d323835322545332538332542424f6d69744279547970652d643939303161" alt="2852・OmitByType"&gt;&lt;/a&gt; &lt;a href="https://github.com/type-challenges/type-challenges/./questions/02946-medium-objectentries/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/75cdd143a14c224cbe963e4d33c81418aae5b90a7caf1c12d03c238d76a75f8f/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d323934362545332538332542424f626a656374456e74726965732d643939303161" alt="2946・ObjectEntries"&gt;&lt;/a&gt; &lt;a href="https://github.com/type-challenges/type-challenges/./questions/03188-medium-tuple-to-nested-object/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/af12e4f2f3f2596a7b36a080493e13d085cb1a40ab3354919e5a2259e51661ef/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d333138382545332538332542425475706c65253230746f2532304e65737465642532304f626a6563742d643939303161" alt="3188・Tuple to Nested Object"&gt;&lt;/a&gt; &lt;a href="https://github.com/type-challenges/type-challenges/./questions/03376-medium-inordertraversal/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/9c97ff922603290566323c20dc8e2103744e61d095db3e0be47908e52f1e2eb6/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d33333736254533253833254242496e6f7264657254726176657273616c2d643939303161" alt="3376・InorderTraversal"&gt;&lt;/a&gt; &lt;a href="https://github.com/type-challenges/type-challenges/./questions/04179-medium-flip/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/fd298f58ca826f970f07d735c42b21a0d0cb10d2ec0ceceb6856af1645c1b525/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d34313739254533253833254242466c69702d643939303161" alt="4179・Flip"&gt;&lt;/a&gt; &lt;a href="https://github.com/type-challenges/type-challenges/./questions/05821-medium-maptypes/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/9f070a2446c6097b943fc7adfd7f6c580429db09109f041e1fa49863673907c1/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d353832312545332538332542424d617054797065732d643939303161" alt="5821・MapTypes"&gt;&lt;/a&gt; &lt;a href="https://github.com/type-challenges/type-challenges/./questions/27932-medium-mergeall/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/d5be71388f3ee70e0270cfab5605edd458ed702f30bc8ea7473ea7bb9ba82d44/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d32373933322545332538332542424d65726765416c6c2d643939303161" alt="27932・MergeAll"&gt;&lt;/a&gt; &lt;a href="https://github.com/type-challenges/type-challenges/./questions/29650-medium-extracttoobject/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/749ccf15dcd2b58aee849a593a00c01d16ed2c857efedf735a739298b4eca966/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d323936353025453325383325424245787472616374546f4f626a6563742d643939303161" alt="29650・ExtractToObject"&gt;&lt;/a&gt; &lt;a href="https://github.com/type-challenges/type-challenges/./questions/02949-hard-objectfromentries/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/835e2bb2741b2b2fe6b57c997947a65ec8f1bf0e11d5f95ab1e5d84e4589e97d/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d323934392545332538332542424f626a65637446726f6d456e74726965732d646533643337" alt="2949・ObjectFromEntries"&gt;&lt;/a&gt; &lt;a href="https://github.com/type-challenges/type-challenges/./questions/09160-hard-assign/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/804b51066cbbce19c83767c21e3c8e9c90b056dd346e0d09a2d33b8bf5e9b0a7/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d3931363025453325383325424241737369676e2d646533643337" alt="9160・Assign"&gt;&lt;/a&gt; &lt;a href="https://github.com/type-challenges/type-challenges/./questions/09775-hard-capitalize-nest-object-keys/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/d252664edf765469592975eb9c99a11bc25babcf71df931f4094e9bdc8ab7df2/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d393737352545332538332542424361706974616c697a652532304e6573742532304f626a6563742532304b6579732d646533643337" alt="9775・Capitalize Nest Object Keys"&gt;&lt;/a&gt; &lt;/td&gt;
&lt;br&gt;
&lt;/tr&gt;
&lt;br&gt;
&lt;tr&gt;
&lt;br&gt;
&lt;td&gt;&lt;a rel="noopener noreferrer nofollow" href="https://camo.githubusercontent.com/0a8b0bca281bae3d745b739f2d0c5f9a2fddfca8bc0bf600cd4db77b4b972cff/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d2532336f626a6563742d2d6b6579732d393939"&gt;&lt;img src="https://camo.githubusercontent.com/0a8b0bca281bae3d745b739f2d0c5f9a2fddfca8bc0bf600cd4db77b4b972cff/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d2532336f626a6563742d2d6b6579732d393939" alt="#object-keys"&gt;&lt;/a&gt;&lt;/td&gt;
&lt;br&gt;
&lt;td&gt;
&lt;br&gt;
&lt;a href="https://github.com/type-challenges/type-challenges/./questions/00007-easy-readonly/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/84c51a27203cd8656e7912ebe93ac836abb21907ed2df8738c26ecc18f9dff81/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d37254533253833254242526561646f6e6c792d376161643063" alt="7・Readonly"&gt;&lt;/a&gt; &lt;a href="https://github.com/type-challenges/type-challenges/./questions/00011-easy-tuple-to-object/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/a484722500934eb028ca5ed7bfa067f88742f9e00abc42e82c65d484ec84f7a7/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d31312545332538332542425475706c65253230746f2532304f626a6563742d376161643063" alt="11・Tuple to Object"&gt;&lt;/a&gt; &lt;a href="https://github.com/type-challenges/type-challenges/./questions/00008-medium-readonly-2/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/f0164a51a8b8ac10a377f5163de611351a0dcfaaae76f5119966e5e71778c5f2/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d38254533253833254242526561646f6e6c79253230322d643939303161" alt="8・Readonly 2"&gt;&lt;/a&gt; &lt;a href="https://github.com/type-challenges/type-challenges/./questions/00009-medium-deep-readonly/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/5f8a5a59fc2ca3e1a95fbe83e5967015270ef541c443c034d3012e87f58ae477/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d3925453325383325424244656570253230526561646f6e6c792d643939303161" alt="9・Deep Readonly"&gt;&lt;/a&gt; &lt;a href="https://github.com/type-challenges/type-challenges/./questions/00527-medium-append-to-object/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/6fa6b24e8d0dcb86fa6497610cc15a5b1f40c1a17bad819538c077cb79b476c6/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d353237254533253833254242417070656e64253230746f2532306f626a6563742d643939303161" alt="527・Append to object"&gt;&lt;/a&gt; &lt;a href="https://github.com/type-challenges/type-challenges/./questions/01130-medium-replacekeys/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/80e38003eb6a163ff2032a3fac10b6ed50bb02f70277bed0f7863ea7d24d153a/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d313133302545332538332542425265706c6163654b6579732d643939303161" alt="1130・ReplaceKeys"&gt;&lt;/a&gt; &lt;a href="https://github.com/type-challenges/type-challenges/./questions/01367-medium-remove-index-signature/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/5b408f33a0365830a9e71ee7eb38d28922fd84fb5af060e3ce58e99ebc64875c/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d3133363725453325383325424252656d6f7665253230496e6465782532305369676e61747572652d643939303161" alt="1367・Remove Index Signature"&gt;&lt;/a&gt; &lt;a href="https://github.com/type-challenges/type-challenges/./questions/02793-medium-mutable/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/dbb8a88395fc2ba73624fb8087b1bab67d9fa7165e8bbe3914f13059d408666c/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d323739332545332538332542424d757461626c652d643939303161" alt="2793・Mutable"&gt;&lt;/a&gt; &lt;a href="https://github.com/type-challenges/type-challenges/./questions/28333-medium-public-type/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/7137f97ee7d7d621326cde5a4bbbdf78b1b552a533c1599451312f627b6a678f/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d32383333332545332538332542425075626c6963253230547970652d643939303161" alt="28333・Public Type"&gt;&lt;/a&gt; &lt;a href="https://github.com/type-challenges/type-challenges/./questions/07258-hard-object-key-paths/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/7896e0b7c50833c974aa92a3a0c76b86f58e2e7dfc3cff9cf1d61b2c07875a24/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d373235382545332538332542424f626a6563742532304b657925323050617468732d646533643337" alt="7258・Object Key Paths"&gt;&lt;/a&gt; &lt;a href="https://github.com/type-challenges/type-challenges/./questions/00005-extreme-readonly-keys/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/02010a018c7e30910ca455004ca2e919f08924b4077f07b9189d5cd48790c806/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d35254533253833254242476574253230526561646f6e6c792532304b6579732d623131623864" alt="5・Get Readonly Keys"&gt;&lt;/a&gt; &lt;/td&gt;
&lt;br&gt;
&lt;/tr&gt;
&lt;br&gt;
&lt;tr&gt;
&lt;br&gt;
&lt;td&gt;&lt;a rel="noopener noreferrer nofollow" href="https://camo.githubusercontent.com/f99e2c66a63d71671aca9cc906cf29b3853d2897040e4fce849c054955d395de/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d2532336f6d69742532306f626a6563742d2d6b657973253230646565702d393939"&gt;&lt;img src="https://camo.githubusercontent.com/f99e2c66a63d71671aca9cc906cf29b3853d2897040e4fce849c054955d395de/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d2532336f6d69742532306f626a6563742d2d6b657973253230646565702d393939" alt="#omit object-keys deep"&gt;&lt;/a&gt;&lt;/td&gt;
&lt;br&gt;
&lt;td&gt;
&lt;br&gt;
&lt;a href="https://github.com/type-challenges/type-challenges/./questions/29785-medium-deep-omit/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/1bc803b865e55289857b42eb9ec47b9791895162dae55b5d48403187727a115d/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d3239373835254533253833254242446565702532304f6d69742d643939303161" alt="29785・Deep Omit"&gt;&lt;/a&gt; &lt;/td&gt;
&lt;br&gt;
&lt;/tr&gt;
&lt;br&gt;
&lt;tr&gt;
&lt;br&gt;
&lt;td&gt;&lt;a rel="noopener noreferrer nofollow" href="https://camo.githubusercontent.com/24b264538da7214d8d1f997c27418c569fba6336cf5491f41b21101c63cb7cd2/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d2532336f7074696f6e616c2d393939"&gt;&lt;img src="https://camo.githubusercontent.com/24b264538da7214d8d1f997c27418c569fba6336cf5491f41b21101c63cb7cd2/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d2532336f7074696f6e616c2d393939" alt="#optional"&gt;&lt;/a&gt;&lt;/td&gt;
&lt;br&gt;
&lt;td&gt;
&lt;br&gt;
&lt;a href="https://github.com/type-challenges/type-challenges/./questions/31997-extreme-parameter-intersection/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/1f0e02704a6ba171842f8fccfb3aecc331e67962fceee6fed8646ad8551cd600/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d3331393937254533253833254242506172616d65746572253230496e74657273656374696f6e2d623131623864" alt="31997・Parameter Intersection"&gt;&lt;/a&gt; &lt;/td&gt;
&lt;br&gt;
&lt;/tr&gt;
&lt;br&gt;
&lt;tr&gt;
&lt;br&gt;
&lt;td&gt;&lt;a rel="noopener noreferrer nofollow" href="https://camo.githubusercontent.com/5f12509ccd22ec29857dc0bce7f7ceb2b6ecc14154a816406deaa26fbdb1ef09/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d253233706172616d65746572732d393939"&gt;&lt;img src="https://camo.githubusercontent.com/5f12509ccd22ec29857dc0bce7f7ceb2b6ecc14154a816406deaa26fbdb1ef09/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d253233706172616d65746572732d393939" alt="#parameters"&gt;&lt;/a&gt;&lt;/td&gt;
&lt;br&gt;
&lt;td&gt;
&lt;br&gt;
&lt;a href="https://github.com/type-challenges/type-challenges/./questions/31997-extreme-parameter-intersection/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/1f0e02704a6ba171842f8fccfb3aecc331e67962fceee6fed8646ad8551cd600/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d3331393937254533253833254242506172616d65746572253230496e74657273656374696f6e2d623131623864" alt="31997・Parameter Intersection"&gt;&lt;/a&gt; &lt;/td&gt;
&lt;br&gt;
&lt;/tr&gt;
&lt;br&gt;
&lt;tr&gt;
&lt;br&gt;
&lt;td&gt;&lt;a rel="noopener noreferrer nofollow" href="https://camo.githubusercontent.com/1215140d967826004029cd3176aeb51c152f2a0137c1a35a0425dd48f9bcc786/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d25323370726f6d6973652d393939"&gt;&lt;img src="https://camo.githubusercontent.com/1215140d967826004029cd3176aeb51c152f2a0137c1a35a0425dd48f9bcc786/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d25323370726f6d6973652d393939" alt="#promise"&gt;&lt;/a&gt;&lt;/td&gt;
&lt;br&gt;
&lt;td&gt;
&lt;br&gt;
&lt;a href="https://github.com/type-challenges/type-challenges/./questions/00189-easy-awaited/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/bbef34543a44abf3666ba55e42426fc297fd5d6b30f75e854dcd14cd7f5ef2bf/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d313839254533253833254242417761697465642d376161643063" alt="189・Awaited"&gt;&lt;/a&gt; &lt;a href="https://github.com/type-challenges/type-challenges/./questions/00020-medium-promise-all/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/0c813d6ca109d17ef474e45f40902463c168693adcdf0d395b945b50dcb5576c/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d323025453325383325424250726f6d6973652e616c6c2d643939303161" alt="20・Promise.all"&gt;&lt;/a&gt; &lt;a href="https://github.com/type-challenges/type-challenges/./questions/32427-hard-unbox/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/ff9f832048e07e7fe6b8e55521cc9942746897b5596a732135ebf62e579bdf84/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d3332343237254533253833254242556e626f782d646533643337" alt="32427・Unbox"&gt;&lt;/a&gt; &lt;/td&gt;
&lt;br&gt;
&lt;/tr&gt;
&lt;br&gt;
&lt;tr&gt;
&lt;br&gt;
&lt;td&gt;&lt;a rel="noopener noreferrer nofollow" href="https://camo.githubusercontent.com/d3ad639d2dff86c713a286357f9d464ec1a66327e3341f363f59a155f4276338/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d253233726561646f6e6c792d393939"&gt;&lt;img src="https://camo.githubusercontent.com/d3ad639d2dff86c713a286357f9d464ec1a66327e3341f363f59a155f4276338/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d253233726561646f6e6c792d393939" alt="#readonly"&gt;&lt;/a&gt;&lt;/td&gt;
&lt;br&gt;
&lt;td&gt;
&lt;br&gt;
&lt;a href="https://github.com/type-challenges/type-challenges/./questions/00007-easy-readonly/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/84c51a27203cd8656e7912ebe93ac836abb21907ed2df8738c26ecc18f9dff81/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d37254533253833254242526561646f6e6c792d376161643063" alt="7・Readonly"&gt;&lt;/a&gt; &lt;a href="https://github.com/type-challenges/type-challenges/./questions/00008-medium-readonly-2/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/f0164a51a8b8ac10a377f5163de611351a0dcfaaae76f5119966e5e71778c5f2/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d38254533253833254242526561646f6e6c79253230322d643939303161" alt="8・Readonly 2"&gt;&lt;/a&gt; &lt;a href="https://github.com/type-challenges/type-challenges/./questions/00009-medium-deep-readonly/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/5f8a5a59fc2ca3e1a95fbe83e5967015270ef541c443c034d3012e87f58ae477/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d3925453325383325424244656570253230526561646f6e6c792d643939303161" alt="9・Deep Readonly"&gt;&lt;/a&gt; &lt;a href="https://github.com/type-challenges/type-challenges/./questions/02793-medium-mutable/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/dbb8a88395fc2ba73624fb8087b1bab67d9fa7165e8bbe3914f13059d408666c/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d323739332545332538332542424d757461626c652d643939303161" alt="2793・Mutable"&gt;&lt;/a&gt; &lt;a href="https://github.com/type-challenges/type-challenges/./questions/17973-medium-deepmutable/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/97731bce386f90914211ef2db326e3df67f11cb85450b03902ec72c69c66aea2/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d3137393733254533253833254242446565704d757461626c652d643939303161" alt="17973・DeepMutable"&gt;&lt;/a&gt; &lt;/td&gt;
&lt;br&gt;
&lt;/tr&gt;
&lt;br&gt;
&lt;tr&gt;
&lt;br&gt;
&lt;td&gt;&lt;a rel="noopener noreferrer nofollow" href="https://camo.githubusercontent.com/813fc33588734cd280878a47eb931f1dd8458e6b38123da0ffb79d733dbd5028/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d253233726563757273696f6e2d393939"&gt;&lt;img src="https://camo.githubusercontent.com/813fc33588734cd280878a47eb931f1dd8458e6b38123da0ffb79d733dbd5028/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d253233726563757273696f6e2d393939" alt="#recursion"&gt;&lt;/a&gt;&lt;/td&gt;
&lt;br&gt;
&lt;td&gt;
&lt;br&gt;
&lt;a href="https://github.com/type-challenges/type-challenges/./questions/21220-medium-permutations-of-tuple/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/3ccad87140b6e85cad78030350db800106fc0d9fc8a4ebe9db5de657a30923cc/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d32313232302545332538332542425065726d75746174696f6e732532306f662532305475706c652d643939303161" alt="21220・Permutations of Tuple"&gt;&lt;/a&gt; &lt;a href="https://github.com/type-challenges/type-challenges/./questions/34007-medium-compare-array-length/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/d60980be0f92b2662acf48c5c08410a72fa45f1cfda2b3c253c244065ff132b2/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d3334303037254533253833254242436f6d7061726525323041727261792532304c656e6774682d643939303161" alt="34007・Compare Array Length"&gt;&lt;/a&gt; &lt;a href="https://github.com/type-challenges/type-challenges/./questions/01383-hard-camelize/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/eda4cb01b58a4fc3986f005809c9fb8a276d8fb70aa52ad8fa352fa7decb6915/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d3133383325453325383325424243616d656c697a652d646533643337" alt="1383・Camelize"&gt;&lt;/a&gt; &lt;a href="https://github.com/type-challenges/type-challenges/./questions/32532-hard-binary-addition/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/88fb9d63f4877ecd2c8dbaacf20659c47e3b5f5bbfb3876631908ba27fb87648/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d333235333225453325383325424242696e6172792532304164646974696f6e2d646533643337" alt="32532・Binary Addition"&gt;&lt;/a&gt; &lt;/td&gt;
&lt;br&gt;
&lt;/tr&gt;
&lt;br&gt;
&lt;tr&gt;
&lt;br&gt;
&lt;td&gt;&lt;a rel="noopener noreferrer nofollow" href="https://camo.githubusercontent.com/3b4afb56ce6516487925baca0c5f2480f5e5c1c3c185372699e4ec753b426edd/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d253233726573742d393939"&gt;&lt;img src="https://camo.githubusercontent.com/3b4afb56ce6516487925baca0c5f2480f5e5c1c3c185372699e4ec753b426edd/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d253233726573742d393939" alt="#rest"&gt;&lt;/a&gt;&lt;/td&gt;
&lt;br&gt;
&lt;td&gt;
&lt;br&gt;
&lt;a href="https://github.com/type-challenges/type-challenges/./questions/31997-extreme-parameter-intersection/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/1f0e02704a6ba171842f8fccfb3aecc331e67962fceee6fed8646ad8551cd600/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d3331393937254533253833254242506172616d65746572253230496e74657273656374696f6e2d623131623864" alt="31997・Parameter Intersection"&gt;&lt;/a&gt; &lt;/td&gt;
&lt;br&gt;
&lt;/tr&gt;
&lt;br&gt;
&lt;tr&gt;
&lt;br&gt;
&lt;td&gt;&lt;a rel="noopener noreferrer nofollow" href="https://camo.githubusercontent.com/f4be8010396fc1f1c06f3efc3ae8cf394beee3307b4ddbc7d6fe7a34db4cffdd/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d25323373706c69742d393939"&gt;&lt;img src="https://camo.githubusercontent.com/f4be8010396fc1f1c06f3efc3ae8cf394beee3307b4ddbc7d6fe7a34db4cffdd/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d25323373706c69742d393939" alt="#split"&gt;&lt;/a&gt;&lt;/td&gt;
&lt;br&gt;
&lt;td&gt;
&lt;br&gt;
&lt;a href="https://github.com/type-challenges/type-challenges/./questions/02822-hard-split/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/df1af9607965c50e51965443c37cc30346af6b7c992600e2a41778f16ff9beb5/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d3238323225453325383325424253706c69742d646533643337" alt="2822・Split"&gt;&lt;/a&gt; &lt;/td&gt;
&lt;br&gt;
&lt;/tr&gt;
&lt;br&gt;
&lt;tr&gt;
&lt;br&gt;
&lt;td&gt;&lt;a rel="noopener noreferrer nofollow" href="https://camo.githubusercontent.com/299337e992bf349f40d49d1c7ebfea444b1d7fa8c499b7f95230d6d26faddc45/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d253233737472696e672d393939"&gt;&lt;img src="https://camo.githubusercontent.com/299337e992bf349f40d49d1c7ebfea444b1d7fa8c499b7f95230d6d26faddc45/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d253233737472696e672d393939" alt="#string"&gt;&lt;/a&gt;&lt;/td&gt;
&lt;br&gt;
&lt;td&gt;
&lt;br&gt;
&lt;a href="https://github.com/type-challenges/type-challenges/./questions/00531-medium-string-to-union/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/0b5dc7a7d7c838fcd1ed696717da0227f1d3b0cf32ab9d0fa11e9c9b92867fa6/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d353331254533253833254242537472696e67253230746f253230556e696f6e2d643939303161" alt="531・String to Union"&gt;&lt;/a&gt; &lt;a href="https://github.com/type-challenges/type-challenges/./questions/08767-medium-combination/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/10fc97eda4d6aa60327a4b794a445c61e9c7b5e89e172fab536c72317b284c09/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d38373637254533253833254242436f6d62696e6174696f6e2d643939303161" alt="8767・Combination"&gt;&lt;/a&gt; &lt;a href="https://github.com/type-challenges/type-challenges/./questions/09142-medium-checkrepeatedchars/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/6edd141426695023e450ccd4eab254d72ce36596f446c9d0a6a0c53afe8f7c4e/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d39313432254533253833254242436865636b526570656174656443686172732d643939303161" alt="9142・CheckRepeatedChars"&gt;&lt;/a&gt; &lt;a href="https://github.com/type-challenges/type-challenges/./questions/09286-medium-firstuniquecharindex/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/0321e5869fff9be339d68ba9fa385dfa36f12dce77585efb7260abf9eef02660/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d393238362545332538332542424669727374556e6971756543686172496e6465782d643939303161" alt="9286・FirstUniqueCharIndex"&gt;&lt;/a&gt; &lt;a href="https://github.com/type-challenges/type-challenges/./questions/09616-medium-parse-url-params/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/75f1b9208d1b0dfc6cdf9ec88e9c9955ef473d3879f58d3c0227183cfac81c48/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d39363136254533253833254242506172736525323055524c253230506172616d732d643939303161" alt="9616・Parse URL Params"&gt;&lt;/a&gt; &lt;a href="https://github.com/type-challenges/type-challenges/./questions/21104-medium-findall/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/351fdce4765b15b8649aa342cf94df528c0a1f3ecf510daf15b4ef7fef6ef67c/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d323131303425453325383325424246696e64416c6c2d643939303161" alt="21104・FindAll"&gt;&lt;/a&gt; &lt;a href="https://github.com/type-challenges/type-challenges/./questions/30301-medium-isodd/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/6f4fc19c53be3dc38e89a5f2c838f617e956da90e918a61f4b064f598c05f600/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d333033303125453325383325424249734f64642d643939303161" alt="30301・IsOdd"&gt;&lt;/a&gt; &lt;a href="https://github.com/type-challenges/type-challenges/./questions/02822-hard-split/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/df1af9607965c50e51965443c37cc30346af6b7c992600e2a41778f16ff9beb5/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d3238323225453325383325424253706c69742d646533643337" alt="2822・Split"&gt;&lt;/a&gt; &lt;a href="https://github.com/type-challenges/type-challenges/./questions/04037-hard-ispalindrome/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/05e1c8cf07677c6f2dddd3f1a9d2ad63619c49d40d1bee4e1113ab26eb315085/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d34303337254533253833254242497350616c696e64726f6d652d646533643337" alt="4037・IsPalindrome"&gt;&lt;/a&gt; &lt;a href="https://github.com/type-challenges/type-challenges/./questions/19458-hard-snakecase/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/20dba8c816b5eb7282ecd0261170dec73632b2631489456836d82fc1a056c1cb/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d3139343538254533253833254242536e616b65436173652d646533643337" alt="19458・SnakeCase"&gt;&lt;/a&gt; &lt;/td&gt;
&lt;br&gt;
&lt;/tr&gt;
&lt;br&gt;
&lt;tr&gt;
&lt;br&gt;
&lt;td&gt;&lt;a rel="noopener noreferrer nofollow" href="https://camo.githubusercontent.com/5bf151ddfde538f8c94a8b31432d03d30ad030642d073e073bbe38fcb9313d60/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d25323374656d706c6174652d2d6c69746572616c2d393939"&gt;&lt;img src="https://camo.githubusercontent.com/5bf151ddfde538f8c94a8b31432d03d30ad030642d073e073bbe38fcb9313d60/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d25323374656d706c6174652d2d6c69746572616c2d393939" alt="#template-literal"&gt;&lt;/a&gt;&lt;/td&gt;
&lt;br&gt;
&lt;td&gt;
&lt;br&gt;
&lt;a href="https://github.com/type-challenges/type-challenges/./questions/00106-medium-trimleft/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/7841b3c493964ed01e3e03f33e8df8a055eb5aa5990ccd7df85d3011f5065353/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d3130362545332538332542425472696d2532304c6566742d643939303161" alt="106・Trim Left"&gt;&lt;/a&gt; &lt;a href="https://github.com/type-challenges/type-challenges/./questions/00108-medium-trim/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/bd510276112778b8016e77dded00ac4f6a8e6ab52744f25c8e5802534c271f33/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d3130382545332538332542425472696d2d643939303161" alt="108・Trim"&gt;&lt;/a&gt; &lt;a href="https://github.com/type-challenges/type-challenges/./questions/00110-medium-capitalize/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/d350ff0ffe7773395072f6899b50ebe7859f2bf549fa13a0f3f06fc0c7903eec/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d3131302545332538332542424361706974616c697a652d643939303161" alt="110・Capitalize"&gt;&lt;/a&gt; &lt;a href="https://github.com/type-challenges/type-challenges/./questions/00116-medium-replace/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/05dd3dbb2d357c31bbf55b1e069002141e655c7880b873d49a792354bcce6a2f/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d3131362545332538332542425265706c6163652d643939303161" alt="116・Replace"&gt;&lt;/a&gt; &lt;a href="https://github.com/type-challenges/type-challenges/./questions/00119-medium-replaceall/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/0847c57f6e903376f9530e249a7cb14ccc8511d6e7eff4aeeb13495c653e0b84/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d3131392545332538332542425265706c616365416c6c2d643939303161" alt="119・ReplaceAll"&gt;&lt;/a&gt; &lt;a href="https://github.com/type-challenges/type-challenges/./questions/00298-medium-length-of-string/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/e521c6ceca0904a0c415ae587fee96bb22e55bbe32cd6d96a1843cd44704c517/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d3239382545332538332542424c656e6774682532306f66253230537472696e672d643939303161" alt="298・Length of String"&gt;&lt;/a&gt; &lt;a href="https://github.com/type-challenges/type-challenges/./questions/00529-medium-absolute/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/3d9badff828ae75c1c5159d33cf82985d01125177245d0ac19e32d76072daac0/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d3532392545332538332542424162736f6c7574652d643939303161" alt="529・Absolute"&gt;&lt;/a&gt; &lt;a href="https://github.com/type-challenges/type-challenges/./questions/00612-medium-kebabcase/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/83cc63664548a730af53834ce5daac8a46d17e3e1f688447c49bf8ffeafcae7e/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d3631322545332538332542424b65626162436173652d643939303161" alt="612・KebabCase"&gt;&lt;/a&gt; &lt;a href="https://github.com/type-challenges/type-challenges/./questions/01978-medium-percentage-parser/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/ee5e30b65ab258b74fe59590f70dc3b32acf995420eb326a972bb618307e65a8/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d3139373825453325383325424250657263656e746167652532305061727365722d643939303161" alt="1978・Percentage Parser"&gt;&lt;/a&gt; &lt;a href="https://github.com/type-challenges/type-challenges/./questions/02070-medium-drop-char/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/e84206550bc23a1481ab72e1a5ead12c007bec35074d341b356da3f1378c7c23/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d3230373025453325383325424244726f70253230436861722d643939303161" alt="2070・Drop Char"&gt;&lt;/a&gt; &lt;a href="https://github.com/type-challenges/type-challenges/./questions/02688-medium-startswith/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/2eee5f124b66a450442055682e4df17e8aa405ee7fdb47bde626803b33520225/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d32363838254533253833254242537461727473576974682d643939303161" alt="2688・StartsWith"&gt;&lt;/a&gt; &lt;a href="https://github.com/type-challenges/type-challenges/./questions/02693-medium-endswith/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/ffb96bd1df29b3a99dab7d786c2bc9e7e787535883b834814f43f4098fe77450/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d32363933254533253833254242456e6473576974682d643939303161" alt="2693・EndsWith"&gt;&lt;/a&gt; &lt;a href="https://github.com/type-challenges/type-challenges/./questions/03326-medium-bem-style-string/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/02a04d366569eb087cb57a7fa07e62ff01547947b5f35c9d84eaf1b1621b4450/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d3333323625453325383325424242454d2532307374796c65253230737472696e672d643939303161" alt="3326・BEM style string"&gt;&lt;/a&gt; &lt;a href="https://github.com/type-challenges/type-challenges/./questions/04260-medium-nomiwase/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/888c5a43fea9fcca69338edea6dfd5a2a3546fdaa45e551925195f59e6ad5794/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d34323630254533253833254242416c6c436f6d62696e6174696f6e732d643939303161" alt="4260・AllCombinations"&gt;&lt;/a&gt; &lt;a href="https://github.com/type-challenges/type-challenges/./questions/04803-medium-trim-right/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/4322711ab44f46b0036a58e2a2c726d9ec8a6482863bfc93cde25b33d3f49205/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d343830332545332538332542425472696d25323052696768742d643939303161" alt="4803・Trim Right"&gt;&lt;/a&gt; &lt;a href="https://github.com/type-challenges/type-challenges/./questions/05140-medium-trunc/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/227caf1add92cd065886d991b591ee59dc678e7d2cd5ba74722e0b16e47ea766/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d353134302545332538332542425472756e632d643939303161" alt="5140・Trunc"&gt;&lt;/a&gt; &lt;a href="https://github.com/type-challenges/type-challenges/./questions/09616-medium-parse-url-params/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/75f1b9208d1b0dfc6cdf9ec88e9c9955ef473d3879f58d3c0227183cfac81c48/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d39363136254533253833254242506172736525323055524c253230506172616d732d643939303161" alt="9616・Parse URL Params"&gt;&lt;/a&gt; &lt;a href="https://github.com/type-challenges/type-challenges/./questions/10969-medium-integer/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/2704f7f1e838c6f9f250b57b913ae7e473793f1669af09fe524cf7a7cc895f22/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d3130393639254533253833254242496e74656765722d643939303161" alt="10969・Integer"&gt;&lt;/a&gt; &lt;a href="https://github.com/type-challenges/type-challenges/./questions/21104-medium-findall/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/351fdce4765b15b8649aa342cf94df528c0a1f3ecf510daf15b4ef7fef6ef67c/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d323131303425453325383325424246696e64416c6c2d643939303161" alt="21104・FindAll"&gt;&lt;/a&gt; &lt;a href="https://github.com/type-challenges/type-challenges/./questions/00112-hard-capitalizewords/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/6016b6f299472f07999016097747b9c93ca988013ed85da20223787d8869edd6/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d3131322545332538332542424361706974616c697a65253230576f7264732d646533643337" alt="112・Capitalize Words"&gt;&lt;/a&gt; &lt;a href="https://github.com/type-challenges/type-challenges/./questions/00114-hard-camelcase/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/62e9f39c4935dd012bf4c560b5c5ac82e2cce327eda966292197d7516610af86/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d31313425453325383325424243616d656c436173652d646533643337" alt="114・CamelCase"&gt;&lt;/a&gt; &lt;a href="https://github.com/type-challenges/type-challenges/./questions/00147-hard-c-printf-parser/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/abc2cb5f78efdfc1a741ca72a9dd30e8695a22cac0b8e0bb0904be2eac9dc0ef/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d313437254533253833254242432d2d7072696e74662532305061727365722d646533643337" alt="147・C-printf Parser"&gt;&lt;/a&gt; &lt;a href="https://github.com/type-challenges/type-challenges/./questions/00270-hard-typed-get/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/02e8493a6b9864d406fd4fbe21e7f05b8ad57f876b30e2d7463f448c15cb825c/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d32373025453325383325424254797065642532304765742d646533643337" alt="270・Typed Get"&gt;&lt;/a&gt; &lt;a href="https://github.com/type-challenges/type-challenges/./questions/00300-hard-string-to-number/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/cf9d8a0e71f195d0a73c32393a4e59e253901f009848ed2f708f16ab6f6217f2/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d333030254533253833254242537472696e67253230746f2532304e756d6265722d646533643337" alt="300・String to Number"&gt;&lt;/a&gt; &lt;a href="https://github.com/type-challenges/type-challenges/./questions/00472-hard-tuple-to-enum-object/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/7159a4227a441b491dd25dd1ead7875dcde5eddb0da7c1f01ca15f3e8ea71ce5/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d3437322545332538332542425475706c65253230746f253230456e756d2532304f626a6563742d646533643337" alt="472・Tuple to Enum Object"&gt;&lt;/a&gt; &lt;a href="https://github.com/type-challenges/type-challenges/./questions/00545-hard-printf/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/22612c1a16a4da8f62159912c2b2ca533d5b7e42c6f5e5c935c525ad11f5a365/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d3534352545332538332542427072696e74662d646533643337" alt="545・printf"&gt;&lt;/a&gt; &lt;a href="https://github.com/type-challenges/type-challenges/./questions/00651-hard-length-of-string-2/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/9d4361dec5c90675a0d975bb49f0f3c2ef0b1b8d23dfcc4930a746f7e8ad1fba/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d3635312545332538332542424c656e6774682532306f66253230537472696e67253230322d646533643337" alt="651・Length of String 2"&gt;&lt;/a&gt; &lt;a href="https://github.com/type-challenges/type-challenges/./questions/02059-hard-drop-string/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/4707d40db5f4668fc3056ba895cbc508b70ca162fde0d9a235ef744139312a59/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d3230353925453325383325424244726f70253230537472696e672d646533643337" alt="2059・Drop String"&gt;&lt;/a&gt; &lt;a href="https://github.com/type-challenges/type-challenges/./questions/19458-hard-snakecase/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/20dba8c816b5eb7282ecd0261170dec73632b2631489456836d82fc1a056c1cb/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d3139343538254533253833254242536e616b65436173652d646533643337" alt="19458・SnakeCase"&gt;&lt;/a&gt; &lt;a href="https://github.com/type-challenges/type-challenges/./questions/25747-hard-isnegativenumber/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/21c1cec3bcd45325d2dff61d073d3737c3d226e460dc5de93bfba3ddd7020143/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d323537343725453325383325424249734e656761746976654e756d6265722d646533643337" alt="25747・IsNegativeNumber"&gt;&lt;/a&gt; &lt;a href="https://github.com/type-challenges/type-challenges/./questions/00151-extreme-query-string-parser/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/f78cb4c1d31807b3605cebb9b4c48dd8094c26326ec77bbf2f690725b2f4aaf5/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d3135312545332538332542425175657279253230537472696e672532305061727365722d623131623864" alt="151・Query String Parser"&gt;&lt;/a&gt; &lt;a href="https://github.com/type-challenges/type-challenges/./questions/00274-extreme-integers-comparator/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/59c32890f5c7ce63eef658134f0334f477a551a3c2d4bb588bdbf3ccd40021fe/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d323734254533253833254242496e746567657273253230436f6d70617261746f722d623131623864" alt="274・Integers Comparator"&gt;&lt;/a&gt; &lt;a href="https://github.com/type-challenges/type-challenges/./questions/00476-extreme-sum/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/0e24d07201087a6fc864577f5922802a991b6662b1cc301a45c15a05920cfca3/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d34373625453325383325424253756d2d623131623864" alt="476・Sum"&gt;&lt;/a&gt; &lt;a href="https://github.com/type-challenges/type-challenges/./questions/00517-extreme-multiply/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/039400e467d7fd3c290123cd1319ee34ff0861a3360f623e69f167dffbd47176/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d3531372545332538332542424d756c7469706c792d623131623864" alt="517・Multiply"&gt;&lt;/a&gt; &lt;a href="https://github.com/type-challenges/type-challenges/./questions/06228-extreme-json-parser/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/445189c078e2d30b5f595baf97b30c22a4912f9ab50bb890d23e0aaabfa4081f/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d363232382545332538332542424a534f4e2532305061727365722d623131623864" alt="6228・JSON Parser"&gt;&lt;/a&gt; &lt;/td&gt;
&lt;br&gt;
&lt;/tr&gt;
&lt;br&gt;
&lt;tr&gt;
&lt;br&gt;
&lt;td&gt;&lt;a rel="noopener noreferrer nofollow" href="https://camo.githubusercontent.com/6d75b1e1c37e675ac65f6a1c444dbab65b6aa27421c0d99cf2649d9ce9d690fe/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d253233746869732d393939"&gt;&lt;img src="https://camo.githubusercontent.com/6d75b1e1c37e675ac65f6a1c444dbab65b6aa27421c0d99cf2649d9ce9d690fe/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d253233746869732d393939" alt="#this"&gt;&lt;/a&gt;&lt;/td&gt;
&lt;br&gt;
&lt;td&gt;
&lt;br&gt;
&lt;a href="https://github.com/type-challenges/type-challenges/./questions/00006-hard-simple-vue/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/11c205500632987f2d5a8e821e0a7e2b8dc80c29207b5504b378419f074beb9f/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d3625453325383325424253696d706c652532305675652d646533643337" alt="6・Simple Vue"&gt;&lt;/a&gt; &lt;a href="https://github.com/type-challenges/type-challenges/./questions/01290-hard-pinia/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/98d7983cead46b6e2752362c22df4c9f7f2662e427a06dfc8295d74984422be4/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d3132393025453325383325424250696e69612d646533643337" alt="1290・Pinia"&gt;&lt;/a&gt; &lt;/td&gt;
&lt;br&gt;
&lt;/tr&gt;
&lt;br&gt;
&lt;tr&gt;
&lt;br&gt;
&lt;td&gt;&lt;a rel="noopener noreferrer nofollow" href="https://camo.githubusercontent.com/0a14ee5f2cdae2a56fa22937dbfcb491c4879fd6092af58bd03dbdeb96aff8db/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d2532337475706c652d393939"&gt;&lt;img src="https://camo.githubusercontent.com/0a14ee5f2cdae2a56fa22937dbfcb491c4879fd6092af58bd03dbdeb96aff8db/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d2532337475706c652d393939" alt="#tuple"&gt;&lt;/a&gt;&lt;/td&gt;
&lt;br&gt;
&lt;td&gt;
&lt;br&gt;
&lt;a href="https://github.com/type-challenges/type-challenges/./questions/00018-easy-tuple-length/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/8279ef38dca0d7d1fc42a16153af6cd32ce6a700cb44f1e0e48a7674bf47c865/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d31382545332538332542424c656e6774682532306f662532305475706c652d376161643063" alt="18・Length of Tuple"&gt;&lt;/a&gt; &lt;a href="https://github.com/type-challenges/type-challenges/./questions/03312-easy-parameters/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/08f4f79c8d4705b83ad15c4ed67dcd36ca5f5b7c8a177a756a1883011b655c87/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d33333132254533253833254242506172616d65746572732d376161643063" alt="3312・Parameters"&gt;&lt;/a&gt; &lt;a href="https://github.com/type-challenges/type-challenges/./questions/00010-medium-tuple-to-union/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/49a65bc299035aa497ee2bacabafb5d229e7c7dd36a89ef03f062589a4660187/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d31302545332538332542425475706c65253230746f253230556e696f6e2d643939303161" alt="10・Tuple to Union"&gt;&lt;/a&gt; &lt;a href="https://github.com/type-challenges/type-challenges/./questions/03188-medium-tuple-to-nested-object/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/af12e4f2f3f2596a7b36a080493e13d085cb1a40ab3354919e5a2259e51661ef/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d333138382545332538332542425475706c65253230746f2532304e65737465642532304f626a6563742d643939303161" alt="3188・Tuple to Nested Object"&gt;&lt;/a&gt; &lt;a href="https://github.com/type-challenges/type-challenges/./questions/03192-medium-reverse/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/b5fc629258301e45c7c51035d7923017889f3ca6592c9ff238bb0093dbd3352d/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d33313932254533253833254242526576657273652d643939303161" alt="3192・Reverse"&gt;&lt;/a&gt; &lt;a href="https://github.com/type-challenges/type-challenges/./questions/03326-medium-bem-style-string/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/02a04d366569eb087cb57a7fa07e62ff01547947b5f35c9d84eaf1b1621b4450/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d3333323625453325383325424242454d2532307374796c65253230737472696e672d643939303161" alt="3326・BEM style string"&gt;&lt;/a&gt; &lt;a href="https://github.com/type-challenges/type-challenges/./questions/04471-medium-zip/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/8d8816c85885c858c43ea9987072b79e5ab5a4cfa0c6f11f0c86360e783b89bf/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d343437312545332538332542425a69702d643939303161" alt="4471・Zip"&gt;&lt;/a&gt; &lt;a href="https://github.com/type-challenges/type-challenges/./questions/04484-medium-istuple/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/aae3bf31b87ca03f5643f9ae66f7fcc93fcfa008f482db300ecb3d0e826e6eea/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d3434383425453325383325424249735475706c652d643939303161" alt="4484・IsTuple"&gt;&lt;/a&gt; &lt;a href="https://github.com/type-challenges/type-challenges/./questions/04499-medium-chunk/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/d930e8911729cf16e4c6ede5168237774661924e448acedba14702e40bc25c1c/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d343439392545332538332542424368756e6b2d643939303161" alt="4499・Chunk"&gt;&lt;/a&gt; &lt;a href="https://github.com/type-challenges/type-challenges/./questions/04518-medium-fill/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/eb28a6e703a3ee3c4326f94f3f598cd77a1e34fe9c172b2887049fd10f8ebdfa/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d3435313825453325383325424246696c6c2d643939303161" alt="4518・Fill"&gt;&lt;/a&gt; &lt;a href="https://github.com/type-challenges/type-challenges/./questions/07544-medium-construct-tuple/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/bf2526a88dfdf86e4fab2830c01aca0fd68b11841aafe8f01f809da9bc6d2437/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d37353434254533253833254242436f6e7374727563742532305475706c652d643939303161" alt="7544・Construct Tuple"&gt;&lt;/a&gt; &lt;a href="https://github.com/type-challenges/type-challenges/./questions/21220-medium-permutations-of-tuple/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/3ccad87140b6e85cad78030350db800106fc0d9fc8a4ebe9db5de657a30923cc/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d32313232302545332538332542425065726d75746174696f6e732532306f662532305475706c652d643939303161" alt="21220・Permutations of Tuple"&gt;&lt;/a&gt; &lt;a href="https://github.com/type-challenges/type-challenges/./questions/27133-medium-square/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/36269f7150538bf2c83a6da2c3edf84f310cee21c08e93234d4720adb9f2f8c6/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d32373133332545332538332542425371756172652d643939303161" alt="27133・Square"&gt;&lt;/a&gt; &lt;a href="https://github.com/type-challenges/type-challenges/./questions/27152-medium-triangular-number/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/87bcfa511b8944ec186e0dea900ca316dcd9ca258a932c0521a77a2bf5efcde7/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d3237313532254533253833254242547269616e67756c61722532306e756d6265722d643939303161" alt="27152・Triangular number"&gt;&lt;/a&gt; &lt;a href="https://github.com/type-challenges/type-challenges/./questions/00399-hard-tuple-filter/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/8488e3b502b85df9daa9365356afcd9e56b3e25c14800dcb114972936dc28edc/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d3339392545332538332542425475706c6525323046696c7465722d646533643337" alt="399・Tuple Filter"&gt;&lt;/a&gt; &lt;a href="https://github.com/type-challenges/type-challenges/./questions/00472-hard-tuple-to-enum-object/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/7159a4227a441b491dd25dd1ead7875dcde5eddb0da7c1f01ca15f3e8ea71ce5/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d3437322545332538332542425475706c65253230746f253230456e756d2532304f626a6563742d646533643337" alt="472・Tuple to Enum Object"&gt;&lt;/a&gt; &lt;a href="https://github.com/type-challenges/type-challenges/./questions/00730-hard-union-to-tuple/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/f8825b6275ff3692389fa7e85a0c0a75c3214f6750ab886f32b8a877ce9cb495/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d373330254533253833254242556e696f6e253230746f2532305475706c652d646533643337" alt="730・Union to Tuple"&gt;&lt;/a&gt; &lt;a href="https://github.com/type-challenges/type-challenges/./questions/02822-hard-split/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/df1af9607965c50e51965443c37cc30346af6b7c992600e2a41778f16ff9beb5/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d3238323225453325383325424253706c69742d646533643337" alt="2822・Split"&gt;&lt;/a&gt; &lt;a href="https://github.com/type-challenges/type-challenges/./questions/30178-hard-unique-items/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/ac72916b5a750b9a29653a81171fac23493819885a11071137ed44cdcd0ddae3/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d3330313738254533253833254242556e697175652532304974656d732d646533643337" alt="30178・Unique Items"&gt;&lt;/a&gt; &lt;a href="https://github.com/type-challenges/type-challenges/./questions/31797-hard-sudoku/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/773ac8cc5a753cc3c34b9d4eebdb40363e8eafb6afc05dfff6a14b00e3c849c3/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d33313739372545332538332542425375646f6b752d646533643337" alt="31797・Sudoku"&gt;&lt;/a&gt; &lt;a href="https://github.com/type-challenges/type-challenges/./questions/32427-hard-unbox/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/ff9f832048e07e7fe6b8e55521cc9942746897b5596a732135ebf62e579bdf84/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d3332343237254533253833254242556e626f782d646533643337" alt="32427・Unbox"&gt;&lt;/a&gt; &lt;a href="https://github.com/type-challenges/type-challenges/./questions/07561-extreme-subtract/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/2124762240a8dc6b8cb97a70446f970ebd1675cde483ad9f45a19e79b701b309/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d3735363125453325383325424253756274726163742d623131623864" alt="7561・Subtract"&gt;&lt;/a&gt; &lt;/td&gt;
&lt;br&gt;
&lt;/tr&gt;
&lt;br&gt;
&lt;tr&gt;
&lt;br&gt;
&lt;td&gt;&lt;a rel="noopener noreferrer nofollow" href="https://camo.githubusercontent.com/d10d3d357995f4e29970b1979b5de6e4fbb5501fc47791283f105910a292adbd/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d253233756e696f6e2d393939"&gt;&lt;img src="https://camo.githubusercontent.com/d10d3d357995f4e29970b1979b5de6e4fbb5501fc47791283f105910a292adbd/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d253233756e696f6e2d393939" alt="#union"&gt;&lt;/a&gt;&lt;/td&gt;
&lt;br&gt;
&lt;td&gt;
&lt;br&gt;
&lt;a href="https://github.com/type-challenges/type-challenges/./questions/00004-easy-pick/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/06d0211585b52905434f4e915f8d1a61c87b3c4cb14b229769424442873cc159/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d342545332538332542425069636b2d376161643063" alt="4・Pick"&gt;&lt;/a&gt; &lt;a href="https://github.com/type-challenges/type-challenges/./questions/00043-easy-exclude/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/ba7e91e317c7798586097785f6fd386eae88932a6dd28dca14c84ab79ce246be/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d34332545332538332542424578636c7564652d376161643063" alt="43・Exclude"&gt;&lt;/a&gt; &lt;a href="https://github.com/type-challenges/type-challenges/./questions/00003-medium-omit/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/6b045a5c99e00480c82029e36f594071ef6b5578d3045eae9d430451f874f530/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d332545332538332542424f6d69742d643939303161" alt="3・Omit"&gt;&lt;/a&gt; &lt;a href="https://github.com/type-challenges/type-challenges/./questions/00010-medium-tuple-to-union/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/49a65bc299035aa497ee2bacabafb5d229e7c7dd36a89ef03f062589a4660187/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d31302545332538332542425475706c65253230746f253230556e696f6e2d643939303161" alt="10・Tuple to Union"&gt;&lt;/a&gt; &lt;a href="https://github.com/type-challenges/type-challenges/./questions/00062-medium-type-lookup/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/23682c391a565041676ad66a5366f0977654629e70a752712502aa4838b93263/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d3632254533253833254242547970652532304c6f6f6b75702d643939303161" alt="62・Type Lookup"&gt;&lt;/a&gt; &lt;a href="https://github.com/type-challenges/type-challenges/./questions/00296-medium-permutation/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/3e139c166215546579505762aa59ddd12f1aa026c55217b76573028dfc7101d3/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d3239362545332538332542425065726d75746174696f6e2d643939303161" alt="296・Permutation"&gt;&lt;/a&gt; &lt;a href="https://github.com/type-challenges/type-challenges/./questions/00531-medium-string-to-union/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/0b5dc7a7d7c838fcd1ed696717da0227f1d3b0cf32ab9d0fa11e9c9b92867fa6/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d353331254533253833254242537472696e67253230746f253230556e696f6e2d643939303161" alt="531・String to Union"&gt;&lt;/a&gt; &lt;a href="https://github.com/type-challenges/type-challenges/./questions/01042-medium-isnever/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/21f70ef723fbe60e50214cc9dfe6161d1cb5c5d705432a7af527f0f42a5e1b3b/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d3130343225453325383325424249734e657665722d643939303161" alt="1042・IsNever"&gt;&lt;/a&gt; &lt;a href="https://github.com/type-challenges/type-challenges/./questions/01097-medium-isunion/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/0cbfaea7428701c0e664579f341749da2ee8911a87296c96e4cc691f93606f24/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d313039372545332538332542424973556e696f6e2d643939303161" alt="1097・IsUnion"&gt;&lt;/a&gt; &lt;a href="https://github.com/type-challenges/type-challenges/./questions/03326-medium-bem-style-string/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/02a04d366569eb087cb57a7fa07e62ff01547947b5f35c9d84eaf1b1621b4450/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d3333323625453325383325424242454d2532307374796c65253230737472696e672d643939303161" alt="3326・BEM style string"&gt;&lt;/a&gt; &lt;a href="https://github.com/type-challenges/type-challenges/./questions/04260-medium-nomiwase/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/888c5a43fea9fcca69338edea6dfd5a2a3546fdaa45e551925195f59e6ad5794/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d34323630254533253833254242416c6c436f6d62696e6174696f6e732d643939303161" alt="4260・AllCombinations"&gt;&lt;/a&gt; &lt;a href="https://github.com/type-challenges/type-challenges/./questions/05117-medium-without/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/0219c277ba35d9a3a37d6e7f3846eba4fa519bc2535d6f19c9847b758cbb28f5/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d35313137254533253833254242576974686f75742d643939303161" alt="5117・Without"&gt;&lt;/a&gt; &lt;a href="https://github.com/type-challenges/type-challenges/./questions/08987-medium-subsequence/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/f62cf306b3ce3357e548e5adae5089e08e99e59041a3ff695ff4021da0c0fb2c/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d3839383725453325383325424253756273657175656e63652d643939303161" alt="8987・Subsequence"&gt;&lt;/a&gt; &lt;a href="https://github.com/type-challenges/type-challenges/./questions/09142-medium-checkrepeatedchars/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/6edd141426695023e450ccd4eab254d72ce36596f446c9d0a6a0c53afe8f7c4e/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d39313432254533253833254242436865636b526570656174656443686172732d643939303161" alt="9142・CheckRepeatedChars"&gt;&lt;/a&gt; &lt;a href="https://github.com/type-challenges/type-challenges/./questions/21220-medium-permutations-of-tuple/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/3ccad87140b6e85cad78030350db800106fc0d9fc8a4ebe9db5de657a30923cc/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d32313232302545332538332542425065726d75746174696f6e732532306f662532305475706c652d643939303161" alt="21220・Permutations of Tuple"&gt;&lt;/a&gt; &lt;a href="https://github.com/type-challenges/type-challenges/./questions/27862-medium-cartesianproduct/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/83043f8e8c38e814ef8bb5f505977c337d6ff8d5466b66ce4156e348977e3da9/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d323738363225453325383325424243617274657369616e50726f647563742d643939303161" alt="27862・CartesianProduct"&gt;&lt;/a&gt; &lt;a href="https://github.com/type-challenges/type-challenges/./questions/27932-medium-mergeall/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/d5be71388f3ee70e0270cfab5605edd458ed702f30bc8ea7473ea7bb9ba82d44/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d32373933322545332538332542424d65726765416c6c2d643939303161" alt="27932・MergeAll"&gt;&lt;/a&gt; &lt;a href="https://github.com/type-challenges/type-challenges/./questions/00730-hard-union-to-tuple/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/f8825b6275ff3692389fa7e85a0c0a75c3214f6750ab886f32b8a877ce9cb495/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d373330254533253833254242556e696f6e253230746f2532305475706c652d646533643337" alt="730・Union to Tuple"&gt;&lt;/a&gt; &lt;a href="https://github.com/type-challenges/type-challenges/./questions/01383-hard-camelize/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/eda4cb01b58a4fc3986f005809c9fb8a276d8fb70aa52ad8fa352fa7decb6915/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d3133383325453325383325424243616d656c697a652d646533643337" alt="1383・Camelize"&gt;&lt;/a&gt; &lt;a href="https://github.com/type-challenges/type-challenges/./questions/05423-hard-intersection/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/c18d0ea98303521e014c20573391c4124d49379956f412b03c1a75977cde8c18/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d35343233254533253833254242496e74657273656374696f6e2d646533643337" alt="5423・Intersection"&gt;&lt;/a&gt; &lt;a href="https://github.com/type-challenges/type-challenges/./questions/31797-hard-sudoku/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/773ac8cc5a753cc3c34b9d4eebdb40363e8eafb6afc05dfff6a14b00e3c849c3/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d33313739372545332538332542425375646f6b752d646533643337" alt="31797・Sudoku"&gt;&lt;/a&gt; &lt;/td&gt;
&lt;br&gt;
&lt;/tr&gt;
&lt;br&gt;
&lt;tr&gt;
&lt;br&gt;
&lt;td&gt;&lt;a rel="noopener noreferrer nofollow" href="https://camo.githubusercontent.com/6b767a203061741f8ccb744cff8380b07534c44be3cd587589b0667f02c3cec6/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d2532337574696c732d393939"&gt;&lt;img src="https://camo.githubusercontent.com/6b767a203061741f8ccb744cff8380b07534c44be3cd587589b0667f02c3cec6/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d2532337574696c732d393939" alt="#utils"&gt;&lt;/a&gt;&lt;/td&gt;
&lt;br&gt;
&lt;td&gt;
&lt;br&gt;
&lt;a href="https://github.com/type-challenges/type-challenges/./questions/00268-easy-if/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/6b89362f2c82ca2e355aee1f51178613edb1b3ec419ce462a44d2b98792962d4/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d32363825453325383325424249662d376161643063" alt="268・If"&gt;&lt;/a&gt; &lt;a href="https://github.com/type-challenges/type-challenges/./questions/01042-medium-isnever/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/21f70ef723fbe60e50214cc9dfe6161d1cb5c5d705432a7af527f0f42a5e1b3b/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d3130343225453325383325424249734e657665722d643939303161" alt="1042・IsNever"&gt;&lt;/a&gt; &lt;a href="https://github.com/type-challenges/type-challenges/./questions/05821-medium-maptypes/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/9f070a2446c6097b943fc7adfd7f6c580429db09109f041e1fa49863673907c1/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d353832312545332538332542424d617054797065732d643939303161" alt="5821・MapTypes"&gt;&lt;/a&gt; &lt;a href="https://github.com/type-challenges/type-challenges/./questions/19749-medium-isequal/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/abab3657260d70361688646c137852587d47c878ceb6771f3ce9f23b6178e9b3/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d31393734392545332538332542424973457175616c2d643939303161" alt="19749・IsEqual"&gt;&lt;/a&gt; &lt;a href="https://github.com/type-challenges/type-challenges/./questions/00055-hard-union-to-intersection/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/e34711b35e8bb219f384cb3ac8401e87123a093f681f2483870224e96730101a/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d3535254533253833254242556e696f6e253230746f253230496e74657273656374696f6e2d646533643337" alt="55・Union to Intersection"&gt;&lt;/a&gt; &lt;a href="https://github.com/type-challenges/type-challenges/./questions/00057-hard-get-required/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/8ca24e948c249fdba977744b2c7f4c3bc3a6a2396b88f785397adee516879c98/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d353725453325383325424247657425323052657175697265642d646533643337" alt="57・Get Required"&gt;&lt;/a&gt; &lt;a href="https://github.com/type-challenges/type-challenges/./questions/00059-hard-get-optional/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/e1ec70cccd26b483e4822810c39723c8f9b6cb2c76fbde7347fd68d156061142/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d35392545332538332542424765742532304f7074696f6e616c2d646533643337" alt="59・Get Optional"&gt;&lt;/a&gt; &lt;a href="https://github.com/type-challenges/type-challenges/./questions/00089-hard-required-keys/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/09f5c85e270866267174fee8aaf9e09c82bd4aaf6271ea78a792d24960d9ceb3/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d383925453325383325424252657175697265642532304b6579732d646533643337" alt="89・Required Keys"&gt;&lt;/a&gt; &lt;a href="https://github.com/type-challenges/type-challenges/./questions/00090-hard-optional-keys/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/f802327306992954f07d0e26abef3fed4fb9e0134ac0a9aafabb51ebf1ce44cf/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d39302545332538332542424f7074696f6e616c2532304b6579732d646533643337" alt="90・Optional Keys"&gt;&lt;/a&gt; &lt;a href="https://github.com/type-challenges/type-challenges/./questions/00223-hard-isany/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/07ad316f7e03b4809017744f1b62c74961bd72f3ee63da5e970607cfcb860158/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d3232332545332538332542424973416e792d646533643337" alt="223・IsAny"&gt;&lt;/a&gt; &lt;a href="https://github.com/type-challenges/type-challenges/./questions/00270-hard-typed-get/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/02e8493a6b9864d406fd4fbe21e7f05b8ad57f876b30e2d7463f448c15cb825c/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d32373025453325383325424254797065642532304765742d646533643337" alt="270・Typed Get"&gt;&lt;/a&gt; &lt;a href="https://github.com/type-challenges/type-challenges/./questions/02828-hard-classpublickeys/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/f9e726db1b5044a464442093dee05ceb3c56a5236260232b32e864751f57cbff/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d32383238254533253833254242436c6173735075626c69634b6579732d646533643337" alt="2828・ClassPublicKeys"&gt;&lt;/a&gt; &lt;a href="https://github.com/type-challenges/type-challenges/./questions/02857-hard-isrequiredkey/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/29cd9fc01f1dd96c358aa57f9931ae7f59b561a64a99f746972cf174c84d6d15/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d32383537254533253833254242497352657175697265644b65792d646533643337" alt="2857・IsRequiredKey"&gt;&lt;/a&gt; &lt;a href="https://github.com/type-challenges/type-challenges/./questions/05181-hard-mutable-keys/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/b1596d8dd9f07e68d9ca791a060d5bc6457d7b0086397a746a84d29621866a61/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d353138312545332538332542424d757461626c652532304b6579732d646533643337" alt="5181・Mutable Keys"&gt;&lt;/a&gt; &lt;a href="https://github.com/type-challenges/type-challenges/./questions/32427-hard-unbox/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/ff9f832048e07e7fe6b8e55521cc9942746897b5596a732135ebf62e579bdf84/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d3332343237254533253833254242556e626f782d646533643337" alt="32427・Unbox"&gt;&lt;/a&gt; &lt;a href="https://github.com/type-challenges/type-challenges/./questions/00005-extreme-readonly-keys/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/02010a018c7e30910ca455004ca2e919f08924b4077f07b9189d5cd48790c806/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d35254533253833254242476574253230526561646f6e6c792532304b6579732d623131623864" alt="5・Get Readonly Keys"&gt;&lt;/a&gt; &lt;/td&gt;
&lt;br&gt;
&lt;/tr&gt;
&lt;br&gt;
&lt;tr&gt;
&lt;br&gt;
&lt;td&gt;&lt;a rel="noopener noreferrer nofollow" href="https://camo.githubusercontent.com/10abb5f77caf26e03693bff6481431f58f1d6d15674def55a9c446bb481ab909/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d25323376617269616469632d393939"&gt;&lt;img src="https://camo.githubusercontent.com/10abb5f77caf26e03693bff6481431f58f1d6d15674def55a9c446bb481ab909/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d25323376617269616469632d393939" alt="#variadic"&gt;&lt;/a&gt;&lt;/td&gt;
&lt;br&gt;
&lt;td&gt;
&lt;br&gt;
&lt;a href="https://github.com/type-challenges/type-challenges/./questions/31997-extreme-parameter-intersection/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/1f0e02704a6ba171842f8fccfb3aecc331e67962fceee6fed8646ad8551cd600/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d3331393937254533253833254242506172616d65746572253230496e74657273656374696f6e2d623131623864" alt="31997・Parameter Intersection"&gt;&lt;/a&gt; &lt;/td&gt;
&lt;br&gt;
&lt;/tr&gt;
&lt;br&gt;
&lt;tr&gt;
&lt;br&gt;
&lt;td&gt;&lt;a rel="noopener noreferrer nofollow" href="https://camo.githubusercontent.com/4a619ac27baca11507ff82d37c1142126005920f8c6cad32c5064c1e179b850e/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d2532337675652d393939"&gt;&lt;img src="https://camo.githubusercontent.com/4a619ac27baca11507ff82d37c1142126005920f8c6cad32c5064c1e179b850e/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d2532337675652d393939" alt="#vue"&gt;&lt;/a&gt;&lt;/td&gt;
&lt;br&gt;
&lt;td&gt;
&lt;br&gt;
&lt;a href="https://github.com/type-challenges/type-challenges/./questions/00006-hard-simple-vue/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/11c205500632987f2d5a8e821e0a7e2b8dc80c29207b5504b378419f074beb9f/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d3625453325383325424253696d706c652532305675652d646533643337" alt="6・Simple Vue"&gt;&lt;/a&gt; &lt;a href="https://github.com/type-challenges/type-challenges/./questions/00213-hard-vue-basic-props/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/fa2dfd2ae83073d83c0a04604b3727f75237624cfc9c0355ca11b4da8f787961/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d323133254533253833254242567565253230426173696325323050726f70732d646533643337" alt="213・Vue Basic Props"&gt;&lt;/a&gt; &lt;a href="https://github.com/type-challenges/type-challenges/./questions/01290-hard-pinia/README.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/98d7983cead46b6e2752362c22df4c9f7f2662e427a06dfc8295d74984422be4/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d3132393025453325383325424250696e69612d646533643337" alt="1290・Pinia"&gt;&lt;/a&gt; &lt;/td&gt;
&lt;br&gt;
&lt;/tr&gt;
&lt;br&gt;
&lt;tr&gt;
&lt;br&gt;
&lt;td&gt;&lt;code&gt;          &lt;/code&gt;&lt;/td&gt;


&lt;/tr&gt;
&lt;br&gt;
&lt;/tbody&gt;&lt;/table&gt;&lt;/div&gt;&lt;br&gt;By Plain Text…&lt;/p&gt;
&lt;/div&gt;
&lt;br&gt;
  &lt;/div&gt;
&lt;br&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/type-challenges/type-challenges" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;br&gt;
&lt;/div&gt;
&lt;br&gt;


&lt;p&gt;These exercises will help you to test and improve your understanding of TypeScript’s type system.&lt;/p&gt;

&lt;h3&gt;
  
  
  Example: &lt;a href="https://github.com/type-challenges/type-challenges/blob/main/questions/00014-easy-first/README.md" rel="noopener noreferrer"&gt;First of Array&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;Let’s look at the “Easy” level challenge. The task is to construct a generic type First that takes an array and returns its first element:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;arr1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;a&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;b&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;c&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;arr2&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;head1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;First&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;arr1&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="c1"&gt;// expected to be 'a'&lt;/span&gt;
&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;head2&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;First&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;arr2&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="c1"&gt;// expected to be 3&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;To solve the task you can use the &lt;a href="https://tsch.js.org/14/play" rel="noopener noreferrer"&gt;Typescript playground&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The solution might be something like this:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;First&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="kr"&gt;any&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;T&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;infer&lt;/span&gt; &lt;span class="nx"&gt;First&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;infer&lt;/span&gt; &lt;span class="nx"&gt;Rest&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="nx"&gt;First&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;never&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;T extends any[]&lt;/code&gt;: We constrain the input T to be an array.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;T extends [infer First, ...infer Rest]&lt;/code&gt;: Pattern matching to extract the first element as First and the rest of the array as Rest.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;First : never&lt;/code&gt;: Conditional type for handling empty arrays.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The &lt;strong&gt;Type Challenges&lt;/strong&gt; repository provides a structured and engaging way to level up your TypeScript mastery.&lt;/p&gt;
&lt;h2&gt;
  
  
  3. Utility types — A collection of pre-written utility types
&lt;/h2&gt;

&lt;p&gt;This collection of pre-written utility types saves you time and effort when working with different data types in TypeScript.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fuezkutw3qkqnunvtiakq.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fuezkutw3qkqnunvtiakq.png" alt="Utility types repository screenshot" width="720" height="181"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This repository offers a collection of utility types that can be applied in various TypeScript projects.&lt;/p&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://assets.dev.to/assets/github-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/piotrwitek" rel="noopener noreferrer"&gt;
        piotrwitek
      &lt;/a&gt; / &lt;a href="https://github.com/piotrwitek/utility-types" rel="noopener noreferrer"&gt;
        utility-types
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      Collection of utility types, complementing TypeScript built-in mapped types and aliases (think "lodash" for static types).
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;
&lt;div&gt;
&lt;div class="markdown-heading"&gt;
&lt;h1 class="heading-element"&gt;utility-types&lt;/h1&gt;
&lt;/div&gt;

&lt;p&gt;Collection of utility types, complementing TypeScript built-in mapped types and aliases (think "lodash" for static types).&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.npmjs.com/package/utility-types" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/4257c85506893a0f3a3ae4230b733860490b23fe1ad8ce687bffbfb4633b42df/68747470733a2f2f696d672e736869656c64732e696f2f6e706d2f762f7574696c6974792d74797065732e737667" alt="Latest Stable Version"&gt;&lt;/a&gt;
&lt;a href="https://www.npmjs.com/package/utility-types" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/936062b7d2e5570de531d0374f3e6c62db5fe8168d11b2c78601019ce1793d27/68747470733a2f2f696d672e736869656c64732e696f2f6e706d2f646d2f7574696c6974792d74797065732e737667" alt="NPM Downloads"&gt;&lt;/a&gt;
&lt;a href="https://www.npmjs.com/package/utility-types" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/9f154a76b63087b903417c4018ea5273e5cdc32ac55c2efb7368d7c046ff82ea/68747470733a2f2f696d672e736869656c64732e696f2f6e706d2f64742f7574696c6974792d74797065732e737667" alt="NPM Downloads"&gt;&lt;/a&gt;
&lt;a href="https://www.npmjs.com/package/utility-types" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/ed0a5422caa281250a9c15df3d4b7f23a604ada22fc1706a20b6d98dd540534c/68747470733a2f2f696d672e736869656c64732e696f2f62756e646c6570686f6269612f6d696e7a69702f7574696c6974792d74797065732e737667" alt="Bundlephobia Size"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="https://github.com/piotrwitek/utility-types/actions/workflows/ci-check.yaml" rel="noopener noreferrer"&gt;&lt;img src="https://github.com/piotrwitek/utility-types/actions/workflows/ci-check.yaml/badge.svg" alt="CI Check"&gt;&lt;/a&gt;
&lt;a href="https://david-dm.org/piotrwitek/utility-types?type=peer" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/7030a9305c92f23bb428adddc217610d0c1ea46740ef80c26a883ee371331991/68747470733a2f2f696d672e736869656c64732e696f2f6e706d2f6c2f7574696c6974792d74797065732e7376673f7374796c653d666c6174" alt="License"&gt;&lt;/a&gt;
&lt;a href="https://spectrum.chat/utility-types" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/f5ded7dabee269d0b1964e3491de6817cdf63a5f9d11bb570ca2cafdc1c2c582/68747470733a2f2f77697468737065637472756d2e6769746875622e696f2f62616467652f62616467652e737667" alt="Join the community on Spectrum"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Found it useful? Want more updates?&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="https://github.com/piotrwitek/utility-types/stargazers" rel="noopener noreferrer"&gt;&lt;strong&gt;Show your support by giving a ⭐&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;
&lt;a href="https://www.buymeacoffee.com/piotrekwitek" rel="nofollow noopener noreferrer"&gt;
  &lt;img src="https://camo.githubusercontent.com/9f44ce2dc3b3eecdd02598900866ffc518801df1932849703dae1e5ce5031070/68747470733a2f2f7777772e6275796d6561636f666665652e636f6d2f6173736574732f696d672f637573746f6d5f696d616765732f6f72616e67655f696d672e706e67" alt="Buy Me a Coffee"&gt;
&lt;/a&gt;
&lt;a href="https://www.patreon.com/piotrekwitek" rel="nofollow noopener noreferrer"&gt;
  &lt;img src="https://camo.githubusercontent.com/56529e692201ddc4f9a8911f23e3d9cc7e9e7536b2c99114d4971f185eaaa6be/68747470733a2f2f63352e70617472656f6e2e636f6d2f65787465726e616c2f6c6f676f2f6265636f6d655f615f706174726f6e5f627574746f6e4032782e706e67" alt="Become a Patron" width="160"&gt;
&lt;/a&gt;


&lt;div class="markdown-heading"&gt;
&lt;h3 class="heading-element"&gt;&lt;strong&gt;What's new?&lt;/strong&gt;&lt;/h3&gt;
&lt;/div&gt;
&lt;p&gt;🎉 &lt;em&gt;Added new utilities&lt;/em&gt; 🎉&lt;/p&gt;

&lt;br&gt;
&lt;/div&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Features&lt;/h2&gt;

&lt;/div&gt;
&lt;ul&gt;
&lt;li&gt;Providing a set of &lt;a href="https://github.com/piotrwitek/utility-types#table-of-contents" rel="noopener noreferrer"&gt;Common Types&lt;/a&gt; for TypeScript projects that are idiomatic and complementary to existing &lt;a href="https://www.typescriptlang.org/docs/handbook/advanced-types.html" rel="nofollow noopener noreferrer"&gt;TypeScript Mapped Types&lt;/a&gt; so you don't need to copy them between the projects.&lt;/li&gt;
&lt;li&gt;Providing a set of &lt;a href="https://github.com/piotrwitek/utility-types#" rel="noopener noreferrer"&gt;Additional Types&lt;/a&gt; compatible with &lt;a href="https://flow.org/en/docs/types/utilities/" rel="nofollow noopener noreferrer"&gt;Flow's Utility Types&lt;/a&gt; to allow much easier migration to &lt;code&gt;TypeScript&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Goals&lt;/h2&gt;

&lt;/div&gt;
&lt;ul&gt;
&lt;li&gt;Quality - thoroughly tested for type correctness with type-testing library &lt;code&gt;dts-jest&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Secure and minimal - no third-party dependencies&lt;/li&gt;
&lt;li&gt;No runtime cost - it's type-level only&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Installation&lt;/h2&gt;

&lt;/div&gt;
&lt;div class="highlight highlight-source-shell notranslate position-relative overflow-auto js-code-highlight"&gt;
&lt;pre&gt;&lt;span class="pl-c"&gt;&lt;span class="pl-c"&gt;#&lt;/span&gt; NPM&lt;/span&gt;
npm install utility-types

&lt;span class="pl-c"&gt;&lt;span class="pl-c"&gt;#&lt;/span&gt; YARN&lt;/span&gt;
yarn add utility-types&lt;/pre&gt;

&lt;/div&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Compatibility Notes&lt;/h2&gt;

&lt;/div&gt;
&lt;p&gt;&lt;strong&gt;TypeScript support&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;v3.x.x&lt;/code&gt; - TypeScript v3.1+&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;v2.x.x&lt;/code&gt; - TypeScript v2.8.1+&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;v1.x.x&lt;/code&gt; - TypeScript v2.7.2+&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Funding Issues&lt;/h2&gt;

&lt;/div&gt;
&lt;p&gt;&lt;strong&gt;Utility-Types&lt;/strong&gt; is an open-source project created by people investing…&lt;/p&gt;
&lt;/div&gt;
  &lt;/div&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/piotrwitek/utility-types" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;


&lt;p&gt;These types exist solely at compile time, leaving no runtime cost in your final JavaScript code.&lt;/p&gt;

&lt;h3&gt;
  
  
  Example: TypeScript Typeguard isPrimitive
&lt;/h3&gt;

&lt;p&gt;First, install utility-types:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install &lt;/span&gt;utility-types
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Let's use &lt;code&gt;isPrimitive&lt;/code&gt; Typeguard example - a TypeScript Typeguard for the &lt;a href="https://github.com/piotrwitek/utility-types#primitive" rel="noopener noreferrer"&gt;&lt;code&gt;Primitive&lt;/code&gt;&lt;/a&gt; type&lt;br&gt;
This can be useful to control the type of a parameter as the program flows.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Primitive&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;isPrimitive&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;utility-types&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;consumer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;param&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Primitive&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nx"&gt;Primitive&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;isPrimitive&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;param&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// typeof param === Primitive&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;param&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt; was Primitive&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="c1"&gt;// typeof param === Primitive[]&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;resultArray&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;param&lt;/span&gt;
        &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;consumer&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;rootString&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="se"&gt;\n\t&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;rootString&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;resultArray&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;reduce&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;comm&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;newV&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;comm&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;newV&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;this was nested:&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;&lt;code&gt;Primitive&lt;/code&gt;: This type represents the basic building blocks of JavaScript and TypeScript values: strings, numbers, booleans, etc.&lt;br&gt;
&lt;code&gt;isPrimitive&lt;/code&gt;: This type guard function lets you dynamically check if a given variable is a primitive type. This is especially valuable when working with data that could have varying structures.&lt;/p&gt;
&lt;h3&gt;
  
  
  Benefits of using utility-types:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Cleaner code: The &lt;code&gt;isPrimitive&lt;/code&gt; type guard avoids manual &lt;code&gt;typeof&lt;/code&gt; checks and potential branching.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Type safety: It ensures that we're only manipulating primitive values within the appropriate code block.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  4. Typescript book — Open-source e-book
&lt;/h2&gt;

&lt;p&gt;Free and open-source e-book that dives deeply into TypeScript's features. Perfect if you prefer a traditional book-like format.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwsdxy5yh0ic4hiznzeti.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwsdxy5yh0ic4hiznzeti.png" alt="Typescript book Logo" width="252" height="54"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You can freely access, read, and even contribute to the book’s content.&lt;/p&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://assets.dev.to/assets/github-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/basarat" rel="noopener noreferrer"&gt;
        basarat
      &lt;/a&gt; / &lt;a href="https://github.com/basarat/typescript-book" rel="noopener noreferrer"&gt;
        typescript-book
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      📚 The definitive guide to TypeScript and possibly the best TypeScript book 📖. Free and Open Source 🌹
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;
&lt;p&gt;&lt;a href="https://www.youtube.com/@basarat" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/3b0a3ac1ba29b24b59f1e7b87f1f9cf85f8c4327f6f3a827d9474fb3b7c009e0/68747470733a2f2f696d672e736869656c64732e696f2f796f75747562652f6368616e6e656c2f73756273637269626572732f554347445f3069364c343868756354696979686235517a513f7374796c653d736f6369616c" alt="YouTube Channel Subscribers"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h1 class="heading-element"&gt;TypeScript Deep Dive&lt;/h1&gt;
&lt;/div&gt;

&lt;p&gt;Learn Professional TypeScript. I've been looking at the issues that turn up commonly when people start using TypeScript. This is based on the lessons from &lt;a href="http://stackoverflow.com/tags/typescript/topusers" rel="nofollow noopener noreferrer"&gt;Stack Overflow&lt;/a&gt; / &lt;a href="https://github.com/DefinitelyTyped/" rel="noopener noreferrer"&gt;DefinitelyTyped&lt;/a&gt; and general engagement with the &lt;a href="https://github.com/TypeStrong/" rel="noopener noreferrer"&gt;TypeScript community&lt;/a&gt;. You can &lt;a href="https://twitter.com/basarat" rel="nofollow noopener noreferrer"&gt;follow for updates&lt;/a&gt; and &lt;a href="https://github.com/basarat/typescript-book" rel="noopener noreferrer"&gt;don't forget to ★ on GitHub&lt;/a&gt; 🌹&lt;/p&gt;

&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Reviews&lt;/h2&gt;
&lt;/div&gt;

&lt;ul&gt;
&lt;li&gt;Thanks for the wonderful book. Learned a lot from it. (&lt;a href="https://www.gitbook.com/book/basarat/typescript/discussions/21#comment-1468279131934" rel="nofollow noopener noreferrer"&gt;link&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;Its probably the Best TypeScript book out there. Good Job (&lt;a href="https://twitter.com/thelondonjs/status/756419561570852864" rel="nofollow noopener noreferrer"&gt;link&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;Love how precise and clear the examples and explanations are! (&lt;a href="https://twitter.com/joe_mighty/status/758290957280346112" rel="nofollow noopener noreferrer"&gt;link&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;For the low, low price of free, you get pages of pure awesomeness. Chock full of source code examples and clear, concise explanations, TypeScript Deep Dive will help you learn TypeScript development. (&lt;a href="https://www.nativescript.org/blog/details/free-book-typescript-deep-dive" rel="nofollow noopener noreferrer"&gt;link&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;Just a big thank you! &lt;strong&gt;Best TypeScript 2 detailed explanation!&lt;/strong&gt; (&lt;a href="https://www.gitbook.com/book/basarat/typescript/discussions/38" rel="nofollow noopener noreferrer"&gt;link&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;This gitbook got my project going pronto. Fluent easy…&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
  &lt;/div&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/basarat/typescript-book" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;


&lt;p&gt;The book is known for its easy-to-understand explanations and illustrative examples. This makes it suitable for both beginners and experienced programmers who want to improve their TypeScript knowledge.&lt;/p&gt;

&lt;p&gt;The book describes various aspects of TypeScript, from its core concepts and syntax to advanced topics like generics, decorators, and metaprogramming.&lt;/p&gt;
&lt;h2&gt;
  
  
  5. &lt;a href="//tRPC.io"&gt;tRPC.io&lt;/a&gt; — End-to-end typesafe API
&lt;/h2&gt;

&lt;p&gt;tRPC offers a solution for building modern APIs with a focus on type safety and developer experience. This open-source project provides tools and libraries needed to construct type-safe APIs.&lt;/p&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://assets.dev.to/assets/github-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/basarat" rel="noopener noreferrer"&gt;
        basarat
      &lt;/a&gt; / &lt;a href="https://github.com/basarat/typescript-book" rel="noopener noreferrer"&gt;
        typescript-book
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      📚 The definitive guide to TypeScript and possibly the best TypeScript book 📖. Free and Open Source 🌹
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;
&lt;p&gt;&lt;a href="https://www.youtube.com/@basarat" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/3b0a3ac1ba29b24b59f1e7b87f1f9cf85f8c4327f6f3a827d9474fb3b7c009e0/68747470733a2f2f696d672e736869656c64732e696f2f796f75747562652f6368616e6e656c2f73756273637269626572732f554347445f3069364c343868756354696979686235517a513f7374796c653d736f6369616c" alt="YouTube Channel Subscribers"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h1 class="heading-element"&gt;TypeScript Deep Dive&lt;/h1&gt;
&lt;/div&gt;
&lt;p&gt;Learn Professional TypeScript. I've been looking at the issues that turn up commonly when people start using TypeScript. This is based on the lessons from &lt;a href="http://stackoverflow.com/tags/typescript/topusers" rel="nofollow noopener noreferrer"&gt;Stack Overflow&lt;/a&gt; / &lt;a href="https://github.com/DefinitelyTyped/" rel="noopener noreferrer"&gt;DefinitelyTyped&lt;/a&gt; and general engagement with the &lt;a href="https://github.com/TypeStrong/" rel="noopener noreferrer"&gt;TypeScript community&lt;/a&gt;. You can &lt;a href="https://twitter.com/basarat" rel="nofollow noopener noreferrer"&gt;follow for updates&lt;/a&gt; and &lt;a href="https://github.com/basarat/typescript-book" rel="noopener noreferrer"&gt;don't forget to ★ on GitHub&lt;/a&gt; 🌹&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Reviews&lt;/h2&gt;
&lt;/div&gt;
&lt;ul&gt;
&lt;li&gt;Thanks for the wonderful book. Learned a lot from it. (&lt;a href="https://www.gitbook.com/book/basarat/typescript/discussions/21#comment-1468279131934" rel="nofollow noopener noreferrer"&gt;link&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;Its probably the Best TypeScript book out there. Good Job (&lt;a href="https://twitter.com/thelondonjs/status/756419561570852864" rel="nofollow noopener noreferrer"&gt;link&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;Love how precise and clear the examples and explanations are! (&lt;a href="https://twitter.com/joe_mighty/status/758290957280346112" rel="nofollow noopener noreferrer"&gt;link&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;For the low, low price of free, you get pages of pure awesomeness. Chock full of source code examples and clear, concise explanations, TypeScript Deep Dive will help you learn TypeScript development. (&lt;a href="https://www.nativescript.org/blog/details/free-book-typescript-deep-dive" rel="nofollow noopener noreferrer"&gt;link&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;Just a big thank you! &lt;strong&gt;Best TypeScript 2 detailed explanation!&lt;/strong&gt; (&lt;a href="https://www.gitbook.com/book/basarat/typescript/discussions/38" rel="nofollow noopener noreferrer"&gt;link&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;This gitbook got my project going pronto. Fluent easy…&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
  &lt;/div&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/basarat/typescript-book" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;


&lt;p&gt;tRPC integrates seamlessly with popular web frameworks such as React, Next.js and Express.js.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fygqqb3wu0pjq80cf7dvu.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fygqqb3wu0pjq80cf7dvu.png" alt="tRPC Example" width="800" height="381"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  Type-safe APIs have several advantages:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Reduced Errors: Static type checking helps catch potential errors at development time, preventing runtime issues that can be difficult to debug later.&lt;/li&gt;
&lt;li&gt;Improved Maintainability: A type-safe API provides a clear understanding of the data structures and interactions involved.&lt;/li&gt;
&lt;li&gt;Enhanced Developer Experience: Autocompletion and other IDE features powered by static types can significantly improve development speed and overall developer satisfaction.&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;Becoming a true TypeScript expert takes time and practice. These resources will help you build a strong start. Keep learning, keep trying new things, and connect with other TypeScript developers to take your skills to the next level.&lt;/p&gt;

&lt;p&gt;Check out my other articles on TypeScript:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://dev.to/alexefimenko/typescript-index-signatures-4-examples-type-safe-dynamic-objects-554o"&gt;TypeScript Index Signatures: 4 Examples Type-Safe Dynamic Objects&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/alexefimenko/3-examples-of-typescript-generic-react-components-4f9"&gt;Making React Components More Flexible with TypeScript Generics: 3 Examples&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/alexefimenko/typescript-enums-5-real-world-use-cases-4idk"&gt;TypeScript Enums: 5 Real-World Use Cases&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This article was originally &lt;a href="https://medium.com/@alexefimenko/5-resources-to-become-an-advanced-typescript-developer-daa2238dad11" rel="noopener noreferrer"&gt;posted on Medium&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>typescript</category>
      <category>webdev</category>
      <category>javascript</category>
      <category>learning</category>
    </item>
    <item>
      <title>Building a File Storage With Next.js, PostgreSQL, and Minio S3</title>
      <dc:creator>Alex</dc:creator>
      <pubDate>Fri, 02 Feb 2024 20:57:51 +0000</pubDate>
      <link>https://dev.to/alexefimenko/building-a-file-storage-with-nextjs-postgresql-and-minio-s3-bla</link>
      <guid>https://dev.to/alexefimenko/building-a-file-storage-with-nextjs-postgresql-and-minio-s3-bla</guid>
      <description>&lt;p&gt;It is the second part of a series of articles about building file storage with Next.js, PostgreSQL, and Minio S3. In &lt;a href="http://blog.alexefimenko.com/posts/nextjs-postgres-s3-locally" rel="noopener noreferrer"&gt;the first part&lt;/a&gt;, we have set up the development environment using Docker Compose. &lt;/p&gt;

&lt;p&gt;In this part, we will build a full-stack application using Next.js, PostgreSQL, and Minio S3. We will build something like this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftafjcrwqi25lqsydklgk.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftafjcrwqi25lqsydklgk.png" alt="File storage app" width="800" height="520"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;In the early days of web development, files like images and documents were stored on the web server along with the application code. However, with increasing user traffic and the need to store large files, cloud storage services like Amazon S3 have become the preferred way to store files.&lt;/p&gt;

&lt;p&gt;Separating the storage of files from the web server provides several benefits, including:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Scalability and performance&lt;/li&gt;
&lt;li&gt;Large file support (up to 5TB)&lt;/li&gt;
&lt;li&gt;Cost efficiency&lt;/li&gt;
&lt;li&gt;Separation of concerns&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In this article, we will build an example of a file storage application using Next.js, PostgreSQL, and Minio S3. There are two main ways to upload files to S3 from Next.js:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Using API routes to upload and download files.&lt;br&gt;
This is a simpler approach, but it has a limitation of 4MB, if you try to upload file more than 4MB, you will get a Next.js error &lt;a href="https://nextjs.org/docs/messages/api-routes-response-size-limit" rel="noopener noreferrer"&gt;"API Routes Response Size Limited to 4MB" Error in Next.js"&lt;/a&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Using presigned URLs to get temporary access to upload files and then upload files directly from frontend to S3.&lt;br&gt;
This approach is a little bit more complex, but it does not use resources on the Next.js server with file uploads.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Source Code
&lt;/h2&gt;

&lt;p&gt;You can find the full source code for this tutorial on &lt;a href="https://github.com/aleksandr-efimenko/local-nextjs-postgres-s3" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Shared code for both approaches
&lt;/h2&gt;

&lt;p&gt;Some code will be shared between the two approaches like UI components, database models, utility functions, and types.&lt;/p&gt;

&lt;h3&gt;
  
  
  Database schema
&lt;/h3&gt;

&lt;p&gt;To save information about the uploaded files, we will create a &lt;code&gt;File&lt;/code&gt; model in the database. In the &lt;code&gt;schema.prisma&lt;/code&gt; file, add the following model:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;model File {
    id           String   @id @default(uuid())
    bucket       String
    fileName     String   @unique
    originalName String
    createdAt    DateTime @default(now())
    size         Int
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;id - the unique identifier of the file in the database generated by the uuid() function.&lt;/li&gt;
&lt;li&gt;bucket - the name of the bucket in S3 where the file is stored, in our case it will be the same for all files.&lt;/li&gt;
&lt;li&gt;fileName - the name of the file in S3, it will be unique for each file. If users upload files with the same name, the new file will overwrite the old one.&lt;/li&gt;
&lt;li&gt;originalName - the original name of the file that the user uploaded. We will use it to display the file name to the user when downloading the file.&lt;/li&gt;
&lt;li&gt;createdAt - the date and time when the file was uploaded.&lt;/li&gt;
&lt;li&gt;size - the size of the file in bytes.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;After creating the model, we need to apply the changes to the database. We can do this using &lt;code&gt;db push&lt;/code&gt; or &lt;code&gt;db migrate&lt;/code&gt; command, the difference between the two commands is that &lt;code&gt;db push&lt;/code&gt; will drop the database and recreate it, while &lt;code&gt;db migrate&lt;/code&gt; will only apply the changes to the database. More information about the commands can be found in &lt;a href="https://www.prisma.io/docs/orm/prisma-migrate/workflows/prototyping-your-schema#choosing-db-push-or-prisma-migrate" rel="noopener noreferrer"&gt;Prisma docs&lt;/a&gt;. In our case it doesn't matter which command we use, so we will use &lt;code&gt;db push&lt;/code&gt; command.&lt;/p&gt;

&lt;h3&gt;
  
  
  Environment variables
&lt;/h3&gt;

&lt;p&gt;If we use Docker Compose to run the application for testing and development, we can store environment variables in the compose file because there is no need to keep them secret. However, in production, we should store environment variables in a &lt;code&gt;.env&lt;/code&gt;.&lt;br&gt;
Here is an example of the &lt;code&gt;.env&lt;/code&gt; file for AWS S3 and PostgreSQL. Replace the values with your own.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;DATABASE_URL="postgresql://postgres:postgres@REMOTESERVERHOST:5432/myapp-db?schema=public"

S3_ENDPOINT="s3.amazonaws.com"
S3_ACCESS_KEY="AKIAIOSFODNN7EXAMPLE"
S3_SECRET_KEY="wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY"
S3_BUCKET_NAME="my-bucket"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For using Google Cloud Storage, the .env file will look like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;S3_ENDPOINT="storage.googleapis.com"
...

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Utility functions and types
&lt;/h3&gt;

&lt;p&gt;Since we are using Minio S3 as the storage service, we need to install the &lt;a href="https://www.npmjs.com/package/minio" rel="noopener noreferrer"&gt;Minio library&lt;/a&gt; to interact with S3. This library is compatible with any S3-compatible storage service, including Amazon S3, Google Cloud Storage, and others.&lt;/p&gt;

&lt;p&gt;Install the Minio library using the following command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install &lt;/span&gt;minio
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then, let's create a utility functions to upload files to Minio S3. Personally, I prefer to create a separate file for utility functions, so I will create a file &lt;code&gt;s3-file-management.ts&lt;/code&gt; in the &lt;code&gt;utils&lt;/code&gt; folder. Here we use included in T3 stack library &lt;a href="https://www.npmjs.com/package/@t3-oss/env-nextjs" rel="noopener noreferrer"&gt;env-nextjs&lt;/a&gt; to validate environment variables.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;Minio&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;minio&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;internal&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;stream&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;env&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;~/env.js&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="c1"&gt;// Create a new Minio client with the S3 endpoint, access key, and secret key&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;s3Client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;Minio&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Client&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;endPoint&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;S3_ENDPOINT&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;port&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;S3_PORT&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="nc"&gt;Number&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;S3_PORT&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;undefined&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;accessKey&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;S3_ACCESS_KEY&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;secretKey&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;S3_SECRET_KEY&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;useSSL&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;S3_USE_SSL&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;true&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;createBucketIfNotExists&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;bucketName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;bucketExists&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;s3Client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;bucketExists&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;bucketName&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;bucketExists&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;s3Client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;makeBucket&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;bucketName&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Main page with file list
&lt;/h3&gt;

&lt;p&gt;The main page will contain the upload form and the list of uploaded files.&lt;/p&gt;

&lt;p&gt;To get the list of files from the database, we will create a function &lt;code&gt;fetchFiles&lt;/code&gt; that sends a GET request to the API route to get the list of files from the database.&lt;/p&gt;

&lt;p&gt;And here is the full code of the main page:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;Head&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;next/head&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;UploadFilesS3PresignedUrl&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;~/components/UploadFilesForm/UploadFilesS3PresignedUrl&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;FilesContainer&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;~/components/FilesContainer&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;useEffect&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;react&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;FileProps&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;~/utils/types&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;UploadFilesRoute&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;~/components/UploadFilesForm/UploadFilesRoute&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;fileUploadMode&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;s3PresignedUrl&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;NextjsAPIEndpoint&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;Home&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;files&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setFiles&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;useState&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;FileProps&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;([])&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;uploadMode&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setUploadMode&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;useState&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;fileUploadMode&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;s3PresignedUrl&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

  &lt;span class="c1"&gt;// Fetch files from the database&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;fetchFiles&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/api/files&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;body&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;FileProps&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;
    &lt;span class="c1"&gt;// set isDeleting to false for all files after fetching&lt;/span&gt;
    &lt;span class="nf"&gt;setFiles&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;file&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;file&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;isDeleting&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt; &lt;span class="p"&gt;})))&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="c1"&gt;// fetch files on the first render&lt;/span&gt;
  &lt;span class="nf"&gt;useEffect&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;fetchFiles&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="k"&gt;catch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;[])&lt;/span&gt;

  &lt;span class="c1"&gt;// determine if we should download using presigned url or Nextjs API endpoint&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;downloadUsingPresignedUrl&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;uploadMode&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;s3PresignedUrl&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
  &lt;span class="c1"&gt;// handle mode change between s3PresignedUrl and NextjsAPIEndpoint&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;handleModeChange&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ChangeEvent&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;HTMLSelectElement&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;setUploadMode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;target&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;fileUploadMode&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Head&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;title&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;File Uploads with Next.js, Prisma, and PostgreSQL&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;title&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;meta&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;'description'&lt;/span&gt; &lt;span class="na"&gt;content&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;'File Uploads with Next.js, Prisma, and PostgreSQL '&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;link&lt;/span&gt; &lt;span class="na"&gt;rel&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;'icon'&lt;/span&gt; &lt;span class="na"&gt;href&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;'/favicon.ico'&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;Head&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;main&lt;/span&gt; &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;'flex min-h-screen items-center justify-center gap-5 font-mono'&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt; &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;'container flex flex-col gap-5 px-3'&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
          &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;ModeSwitchMenu&lt;/span&gt; &lt;span class="na"&gt;uploadMode&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;uploadMode&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="na"&gt;handleModeChange&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;handleModeChange&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
          &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;uploadMode&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;s3PresignedUrl&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;UploadFilesS3PresignedUrl&lt;/span&gt; &lt;span class="na"&gt;onUploadSuccess&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;fetchFiles&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
          &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;UploadFilesRoute&lt;/span&gt; &lt;span class="na"&gt;onUploadSuccess&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;fetchFiles&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
          &lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
          &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;FilesContainer&lt;/span&gt;
            &lt;span class="na"&gt;files&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;files&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
            &lt;span class="na"&gt;fetchFiles&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;fetchFiles&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
            &lt;span class="na"&gt;setFiles&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;setFiles&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
            &lt;span class="na"&gt;downloadUsingPresignedUrl&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;downloadUsingPresignedUrl&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
          &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;main&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;/&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  API route to get list of files from the database
&lt;/h3&gt;

&lt;p&gt;To make request to the database, we need to create an API route. Create a file &lt;code&gt;index.ts&lt;/code&gt; in the &lt;code&gt;pages/api/files&lt;/code&gt; folder. This file will return the list of files from the database. For simplicity, we will not use pagination, we just get the 10 latest files from the database.&lt;br&gt;
You can implement it using skip and take. More information about pagination can be found in the &lt;a href="https://www.prisma.io/docs/concepts/components/prisma-client/pagination#skip-and-take" rel="noopener noreferrer"&gt;Prisma docs&lt;/a&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;NextApiRequest&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;NextApiResponse&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;next&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;FileProps&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;~/utils/types&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;db&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;~/server/db&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;LIMIT_FILES&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;handler&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;NextApiRequest&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;NextApiResponse&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// Get the 10 latest files from the database&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;files&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;file&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;findMany&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;take&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;LIMIT_FILES&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;orderBy&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;createdAt&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;desc&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="na"&gt;select&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;originalName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;size&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;})&lt;/span&gt;
  &lt;span class="c1"&gt;// The database type is a bit different from the frontend type&lt;/span&gt;
  &lt;span class="c1"&gt;// Make the array of files compatible with the frontend type FileProps&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="na"&gt;filesWithProps&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;FileProps&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;files&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;file&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;file&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;originalFileName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;file&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;originalName&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;fileSize&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;file&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;size&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;}))&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;status&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;filesWithProps&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nx"&gt;handler&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Mode switch menu
&lt;/h3&gt;

&lt;p&gt;The mode switch menu will allow the user to switch between the two approaches for uploading files.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;ModeSwitchMenuProps&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;uploadMode&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;fileUploadMode&lt;/span&gt;
  &lt;span class="na"&gt;handleModeChange&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="na"&gt;event&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ChangeEvent&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;HTMLSelectElement&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;ModeSwitchMenu&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;uploadMode&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;handleModeChange&lt;/span&gt; &lt;span class="p"&gt;}:&lt;/span&gt; &lt;span class="nx"&gt;ModeSwitchMenuProps&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;ul&lt;/span&gt; &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;'flex items-center justify-center gap-2'&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;li&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;label&lt;/span&gt; &lt;span class="na"&gt;htmlFor&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;'uploadMode'&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;Upload Mode:&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;label&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;li&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;li&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;select&lt;/span&gt;
          &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;'rounded-md border-2 border-gray-300'&lt;/span&gt;
          &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;'uploadMode'&lt;/span&gt;
          &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;uploadMode&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
          &lt;span class="na"&gt;onChange&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;handleModeChange&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
          &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;option&lt;/span&gt; &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;'s3PresignedUrl'&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;S3 Presigned Url&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;option&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
          &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;option&lt;/span&gt; &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;'NextjsAPIEndpoint'&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;Next.js API Endpoint&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;option&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;select&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;li&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;ul&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  File item UI
&lt;/h3&gt;

&lt;p&gt;To display the files, we will create a component &lt;code&gt;FileItem.tsx&lt;/code&gt; that will display the file name, size, and a delete button. Here is a simplified version of the file without functions to download and delete files. These functions will be added later.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;FileProps&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;~/utils/types&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;LoadSpinner&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./LoadSpinner&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;formatBytes&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;~/utils/fileUploadHelpers&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;FileItemProps&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;file&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;FileProps&lt;/span&gt;
  &lt;span class="na"&gt;fetchFiles&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;void&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="na"&gt;setFiles&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="na"&gt;files&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;FileProps&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="na"&gt;files&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;FileProps&lt;/span&gt;&lt;span class="p"&gt;[])&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;FileProps&lt;/span&gt;&lt;span class="p"&gt;[]))&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt;
  &lt;span class="na"&gt;downloadUsingPresignedUrl&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;boolean&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;FileItem&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;file&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;fetchFiles&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setFiles&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;downloadUsingPresignedUrl&lt;/span&gt; &lt;span class="p"&gt;}:&lt;/span&gt; &lt;span class="nx"&gt;FileItemProps&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;li&lt;/span&gt; &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;'relative flex items-center justify-between gap-2 border-b py-2 text-sm'&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;button&lt;/span&gt;
        &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;'truncate text-blue-500 hover:text-blue-600 hover:underline  '&lt;/span&gt;
        &lt;span class="na"&gt;onClick&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;downloadFile&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;file&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
      &lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;file&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;originalFileName&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;button&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;

      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt; &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;' flex items-center gap-2'&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;span&lt;/span&gt; &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;'w-32 '&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nf"&gt;formatBytes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;file&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;fileSize&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;span&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;

        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;button&lt;/span&gt;
          &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="err"&gt;'&lt;/span&gt;&lt;span class="na"&gt;flex&lt;/span&gt; &lt;span class="na"&gt;w-full&lt;/span&gt; &lt;span class="na"&gt;flex-1&lt;/span&gt; &lt;span class="na"&gt;cursor-pointer&lt;/span&gt; &lt;span class="na"&gt;items-center&lt;/span&gt; &lt;span class="na"&gt;justify-center&lt;/span&gt;
           &lt;span class="na"&gt;rounded-md&lt;/span&gt; &lt;span class="na"&gt;bg-red-500&lt;/span&gt; &lt;span class="na"&gt;px-4&lt;/span&gt; &lt;span class="na"&gt;py-2&lt;/span&gt; &lt;span class="na"&gt;text-white&lt;/span&gt; &lt;span class="na"&gt;hover&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt;&lt;span class="na"&gt;bg-red-600&lt;/span&gt;
           &lt;span class="na"&gt;disabled&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt;&lt;span class="na"&gt;cursor-not-allowed&lt;/span&gt; &lt;span class="na"&gt;disabled&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt;&lt;span class="na"&gt;opacity-50&lt;/span&gt;&lt;span class="err"&gt;'&lt;/span&gt;
          &lt;span class="na"&gt;onClick&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;deleteFile&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;file&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
          &lt;span class="na"&gt;disabled&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;file&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;isDeleting&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
          Delete
        &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;button&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;

      &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;file&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;isDeleting&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt; &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;'absolute inset-0 flex items-center justify-center rounded-md bg-gray-900 bg-opacity-20'&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
          &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;LoadSpinner&lt;/span&gt; &lt;span class="na"&gt;size&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;'small'&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;li&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  File container UI
&lt;/h3&gt;

&lt;p&gt;To display the files, we will create a component &lt;code&gt;FileContainer.tsx&lt;/code&gt; that will display the list of files using the &lt;code&gt;FileItem&lt;/code&gt; component.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;FilesListProps&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;~/utils/types&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;FileItem&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./FileItem&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;FilesContainer&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;files&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;fetchFiles&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setFiles&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;downloadUsingPresignedUrl&lt;/span&gt; &lt;span class="p"&gt;}:&lt;/span&gt; &lt;span class="nx"&gt;FilesListProps&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;files&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt; &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;'flex h-96 flex-col items-center justify-center '&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt; &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;'text-xl'&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;No files uploaded yet&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt; &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;'h-96'&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;h1&lt;/span&gt; &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;'text-xl '&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        Last &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;files&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; uploaded file&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;files&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;s&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;''&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;h1&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;ul&lt;/span&gt; &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;'h-80 overflow-auto'&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;files&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;file&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
          &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;FileItem&lt;/span&gt;
            &lt;span class="na"&gt;key&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;file&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
            &lt;span class="na"&gt;file&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;file&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
            &lt;span class="na"&gt;fetchFiles&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;fetchFiles&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
            &lt;span class="na"&gt;setFiles&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;setFiles&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
            &lt;span class="na"&gt;downloadUsingPresignedUrl&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;downloadUsingPresignedUrl&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
          &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;ul&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Upload form UI
&lt;/h3&gt;

&lt;p&gt;To upload files, we will create a form with a file input field. &lt;code&gt;UploadFilesFormUI.tsx&lt;/code&gt; will contain the UI for the upload form which will be used in both approaches. Here is a simplified version of the file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;Link&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;next/link&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;LoadSpinner&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;../LoadSpinner&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;UploadFilesFormUIProps&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;~/utils/types&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;UploadFilesFormUI&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;isLoading&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;fileInputRef&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;uploadToServer&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;maxFileSize&lt;/span&gt; &lt;span class="p"&gt;}:&lt;/span&gt; &lt;span class="nx"&gt;UploadFilesFormUIProps&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;form&lt;/span&gt; &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;'flex flex-col items-center justify-center gap-3'&lt;/span&gt; &lt;span class="na"&gt;onSubmit&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;uploadToServer&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;h1&lt;/span&gt; &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;'text-2xl'&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;File upload example using Next.js, MinIO S3, Prisma and PostgreSQL&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;h1&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;isLoading&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;LoadSpinner&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt; &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;'flex h-16 gap-5'&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
          &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;input&lt;/span&gt;
            &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;'file'&lt;/span&gt;
            &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;'file'&lt;/span&gt;
            &lt;span class="na"&gt;multiple&lt;/span&gt;
            &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;'rounded-md border bg-gray-100 p-2 py-5'&lt;/span&gt;
            &lt;span class="na"&gt;required&lt;/span&gt;
            &lt;span class="na"&gt;ref&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;fileInputRef&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
          &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
          &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;button&lt;/span&gt;
            &lt;span class="na"&gt;disabled&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;isLoading&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
            &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="err"&gt;'&lt;/span&gt;&lt;span class="na"&gt;m-2&lt;/span&gt; &lt;span class="na"&gt;rounded-md&lt;/span&gt; &lt;span class="na"&gt;bg-blue-500&lt;/span&gt; &lt;span class="na"&gt;px-5&lt;/span&gt; &lt;span class="na"&gt;py-2&lt;/span&gt; &lt;span class="na"&gt;text-white&lt;/span&gt;
                &lt;span class="na"&gt;hover&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt;&lt;span class="na"&gt;bg-blue-600&lt;/span&gt;  &lt;span class="na"&gt;disabled&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt;&lt;span class="na"&gt;cursor-not-allowed&lt;/span&gt; &lt;span class="na"&gt;disabled&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt;&lt;span class="na"&gt;bg-gray-400&lt;/span&gt;&lt;span class="err"&gt;'&lt;/span&gt;
          &lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
            Upload
          &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;button&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;form&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  1.1 Upload files using Next.js API routes (4MB limit)
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fw6w7qemlnscipr5mh6rx.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fw6w7qemlnscipr5mh6rx.png" alt="Upload files using Next.js API route" width="800" height="440"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The diagram above shows the steps involved in uploading and downloading files using Next.js API routes.&lt;/p&gt;

&lt;p&gt;To upload files:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;User sends a POST request to the API route with the file to upload.&lt;/li&gt;
&lt;li&gt;The API route uploads the file to S3 and returns the file name.&lt;/li&gt;
&lt;li&gt;The file name is saved in the database.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Frontend - Upload form logic for API routes
&lt;/h3&gt;

&lt;p&gt;First, we will create a &lt;code&gt;UploadFilesRoute.tsx&lt;/code&gt; file with the logic for the upload form.&lt;/p&gt;

&lt;p&gt;The algorithm for uploading files to the server is as follows:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;The user selects files to upload, and the &lt;code&gt;fileInputRef&lt;/code&gt; is updated with the selected files.&lt;/li&gt;
&lt;li&gt;Form data is created from the selected files using the &lt;code&gt;createFormData&lt;/code&gt; function and &lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/FormData" rel="noopener noreferrer"&gt;FormData&lt;/a&gt; API.&lt;/li&gt;
&lt;li&gt;The form data is sent to the server using POST request to the &lt;code&gt;/api/files/upload/smallFiles&lt;/code&gt; route.&lt;/li&gt;
&lt;li&gt;The server uploads the files to S3 and returns status and message in the response.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;It's usually a good idea to extract the logic of the UI component into a separate file. One way is to create hooks for the logic and use the hooks in the UI component, however, for simplicity, we will create a separate file for the logic "fileUploadHelpers.ts" and use it in the "UploadFilesRoute" component.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="cm"&gt;/**
 * Create form data from files
 * @param files files to upload
 * @returns form data
 */&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;createFormData&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;files&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;File&lt;/span&gt;&lt;span class="p"&gt;[]):&lt;/span&gt; &lt;span class="nx"&gt;FormData&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;formData&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;FormData&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
  &lt;span class="nx"&gt;files&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;forEach&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;file&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;formData&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;file&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;file&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;})&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;formData&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here is a simplified version, without validation, loading state and error handling:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;useRef&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;react&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;validateFiles&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;createFormData&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;~/utils/fileUploadHelpers&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;MAX_FILE_SIZE_NEXTJS_ROUTE&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;~/utils/fileUploadHelpers&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;UploadFilesFormUI&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./UploadFilesFormUI&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;UploadFilesFormProps&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;onUploadSuccess&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;UploadFilesRoute&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;onUploadSuccess&lt;/span&gt; &lt;span class="p"&gt;}:&lt;/span&gt; &lt;span class="nx"&gt;UploadFilesFormProps&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;fileInputRef&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;useRef&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;HTMLInputElement&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;uploadToServer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;FormEvent&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;HTMLFormElement&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;preventDefault&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;files&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Object&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;values&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;fileInputRef&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;current&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;files&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;formData&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;createFormData&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;files&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/api/files/upload/smallFiles&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;method&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;POST&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;body&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;formData&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;})&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;body&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;status&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;ok&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;fail&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
      &lt;span class="na"&gt;message&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;UploadFilesFormUI&lt;/span&gt;
      &lt;span class="na"&gt;isLoading&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;isLoading&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
      &lt;span class="na"&gt;fileInputRef&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;fileInputRef&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
      &lt;span class="na"&gt;uploadToServer&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;uploadToServer&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
      &lt;span class="na"&gt;maxFileSize&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;MAX_FILE_SIZE_NEXTJS_ROUTE&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Check the full code in the &lt;a href="https://github.com/aleksandr-efimenko/local-nextjs-postgres-s3/blob/main/src/components/UploadFilesForm/UploadFilesRoute.tsx" rel="noopener noreferrer"&gt;GitHub repository&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Backend - Upload files using Next.js API routes
&lt;/h3&gt;

&lt;h4&gt;
  
  
  1. Create utility functions to upload files using Minio S3
&lt;/h4&gt;

&lt;p&gt;To upload files to S3, we will create a utility function &lt;code&gt;saveFileInBucket&lt;/code&gt; that uses the &lt;a href="https://min.io/docs/minio/linux/developers/javascript/API.html#putobject-bucketname-objectname-stream-size-metadata-callback" rel="noopener noreferrer"&gt;&lt;code&gt;putObject&lt;/code&gt; method&lt;/a&gt; of the Minio client to upload the file to the S3 bucket. The function &lt;code&gt;createBucketIfNotExists&lt;/code&gt; creates a bucket if it doesn't exist.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="cm"&gt;/**
 * Save file in S3 bucket
 * @param bucketName name of the bucket
 * @param fileName name of the file
 * @param file file to save
 */&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;saveFileInBucket&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="nx"&gt;bucketName&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;fileName&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;file&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;}:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;bucketName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;
  &lt;span class="nx"&gt;fileName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;
  &lt;span class="nx"&gt;file&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Buffer&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nx"&gt;internal&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Readable&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// Create bucket if it doesn't exist&lt;/span&gt;
  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;createBucketIfNotExists&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;bucketName&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

  &lt;span class="c1"&gt;// check if file exists - optional.&lt;/span&gt;
  &lt;span class="c1"&gt;// Without this check, the file will be overwritten if it exists&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;fileExists&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;checkFileExistsInBucket&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="nx"&gt;bucketName&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;fileName&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;})&lt;/span&gt;

  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;fileExists&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;File already exists&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="c1"&gt;// Upload image to S3 bucket&lt;/span&gt;
  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;s3Client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;putObject&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;bucketName&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;fileName&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;file&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="cm"&gt;/**
 * Check if file exists in bucket
 * @param bucketName name of the bucket
 * @param fileName name of the file
 * @returns true if file exists, false if not
 */&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;checkFileExistsInBucket&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;bucketName&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;fileName&lt;/span&gt; &lt;span class="p"&gt;}:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nl"&gt;bucketName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nl"&gt;fileName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;s3Client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;statObject&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;bucketName&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;fileName&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  2. Create an API route to upload files
&lt;/h4&gt;

&lt;p&gt;Next, we will create an API route to handle file uploads. Create a file &lt;code&gt;smallFiles.ts&lt;/code&gt; in the &lt;code&gt;pages/api/files/upload&lt;/code&gt; folder. This file will do both the file upload and save the file name in the database.&lt;/p&gt;

&lt;p&gt;To parse the incoming request, we will use the &lt;a href="https://www.npmjs.com/package/formidable" rel="noopener noreferrer"&gt;formidable&lt;/a&gt; library. Formidable is a Node.js module for parsing form data, especially file uploads.&lt;/p&gt;

&lt;p&gt;The algorithm for uploading files to the server&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Get files from the request using formidable.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Then, for each file:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Read the file from the file path using &lt;code&gt;fs.createReadStream&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Generate a unique file name using the &lt;a href="https://www.npmjs.com/package/nanoid" rel="noopener noreferrer"&gt;nanoid&lt;/a&gt; library.&lt;/li&gt;
&lt;li&gt;Save the file to S3 using the &lt;code&gt;saveFileInBucket&lt;/code&gt; function that invokes the &lt;code&gt;putObject&lt;/code&gt; method of the Minio client.&lt;/li&gt;
&lt;li&gt;Save the file info to the database using Prisma &lt;code&gt;file.create&lt;/code&gt; method.&lt;/li&gt;
&lt;li&gt;Return the status and message in the response to the client.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The file upload and saving the file info to the database will be done concurrently using &lt;code&gt;Promise.all&lt;/code&gt;. Also consider using &lt;code&gt;Promise.allSettled&lt;/code&gt; to handle errors in the file upload and saving the file info to the database.&lt;/p&gt;

&lt;p&gt;If an error occurs during the file upload or saving the file info to the database, we will set the status to 500 and return an error message.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;NextApiRequest&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;NextApiResponse&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;next&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;fs&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;fs&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;IncomingForm&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;File&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;formidable&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;env&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;~/env&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;saveFileInBucket&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;~/utils/s3-file-management&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;nanoid&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;nanoid&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;db&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;~/server/db&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;bucketName&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;S3_BUCKET_NAME&lt;/span&gt;

&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;ProcessedFiles&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Array&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;File&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;handler&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;NextApiRequest&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;NextApiResponse&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;status&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;resultBody&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;status&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;ok&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;message&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Files were uploaded successfully&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="c1"&gt;// Get files from request using formidable&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;files&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;ProcessedFiles&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="kc"&gt;undefined&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;reject&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;form&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;IncomingForm&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="na"&gt;files&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;ProcessedFiles&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;
    &lt;span class="nx"&gt;form&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;on&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;file&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nf"&gt;function &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;field&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;file&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;files&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="nx"&gt;field&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;file&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
    &lt;span class="p"&gt;})&lt;/span&gt;
    &lt;span class="nx"&gt;form&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;on&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;end&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;files&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="nx"&gt;form&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;on&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;error&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;reject&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="nx"&gt;form&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;parse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="c1"&gt;//&lt;/span&gt;
    &lt;span class="p"&gt;})&lt;/span&gt;
  &lt;span class="p"&gt;}).&lt;/span&gt;&lt;span class="k"&gt;catch&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="p"&gt;;({&lt;/span&gt; &lt;span class="nx"&gt;status&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;resultBody&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;setErrorStatus&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;status&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;resultBody&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;undefined&lt;/span&gt;
  &lt;span class="p"&gt;})&lt;/span&gt;

  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;files&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// Upload files to S3 bucket&lt;/span&gt;
    &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;all&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="nx"&gt;files&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="nx"&gt;_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;fileObject&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;file&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;fs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createReadStream&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;fileObject&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;filepath&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
          &lt;span class="c1"&gt;// generate unique file name&lt;/span&gt;
          &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;fileName&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nf"&gt;nanoid&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;)}&lt;/span&gt;&lt;span class="s2"&gt;-&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;fileObject&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;originalFilename&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;
          &lt;span class="c1"&gt;// Save file to S3 bucket and save file info to database concurrently&lt;/span&gt;
          &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;saveFileInBucket&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
            &lt;span class="nx"&gt;bucketName&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="nx"&gt;fileName&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="nx"&gt;file&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="p"&gt;})&lt;/span&gt;
          &lt;span class="c1"&gt;// save file info to database&lt;/span&gt;
          &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;file&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
            &lt;span class="na"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
              &lt;span class="na"&gt;bucket&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;bucketName&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
              &lt;span class="nx"&gt;fileName&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
              &lt;span class="na"&gt;originalName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;fileObject&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;originalFilename&lt;/span&gt; &lt;span class="o"&gt;??&lt;/span&gt; &lt;span class="nx"&gt;fileName&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
              &lt;span class="na"&gt;size&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;fileObject&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;size&lt;/span&gt; &lt;span class="o"&gt;??&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="p"&gt;},&lt;/span&gt;
          &lt;span class="p"&gt;})&lt;/span&gt;
        &lt;span class="p"&gt;})&lt;/span&gt;
      &lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="p"&gt;;({&lt;/span&gt; &lt;span class="nx"&gt;status&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;resultBody&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;setErrorStatus&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;status&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;resultBody&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;status&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;status&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;resultBody&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// Set error status and result body if error occurs&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;setErrorStatus&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;status&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;resultBody&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nl"&gt;status&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nl"&gt;message&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;status&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;500&lt;/span&gt;
  &lt;span class="nx"&gt;resultBody&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;status&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;fail&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;message&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Upload error&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;status&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;resultBody&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// Disable body parser built-in to Next.js to allow formidable to work&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;config&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;api&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;bodyParser&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nx"&gt;handler&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Remember to include &lt;code&gt;export const config&lt;/code&gt;, this prevents built-in body parser of Next.js from parsing the request body, which allows formidable to work.&lt;/p&gt;

&lt;h2&gt;
  
  
  1.2 Download files using Next.js API routes (4MB limit)
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzj86pdrz4xa96t57brlm.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzj86pdrz4xa96t57brlm.png" alt="Download files using Next.js API route" width="800" height="430"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;To download files:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;User sends a GET request to the API route with the file id to download.&lt;/li&gt;
&lt;li&gt;The API route requests the file name from the database.&lt;/li&gt;
&lt;li&gt;The API route downloads the file from S3.&lt;/li&gt;
&lt;li&gt;The file is piped to the response object and returned to the client.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Frontend - Download files using Next.js API routes
&lt;/h3&gt;

&lt;p&gt;To download files, we will create a function &lt;code&gt;downloadFile&lt;/code&gt; inside of the FileItem component. The function sends a GET request to the API route to download the file from S3. The file is returned to the user from the API route.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;downloadFile&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;file&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;FileProps&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`/api/files/download/smallFiles/&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;file&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;_blank&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Backend - Download files using Next.js API routes
&lt;/h3&gt;

&lt;h4&gt;
  
  
  1. Create a utility function to download files from S3
&lt;/h4&gt;

&lt;p&gt;To download files from S3, we will create a utility function &lt;code&gt;getFileFromBucket&lt;/code&gt; that uses the &lt;a href="https://min.io/docs/minio/javascript-client-api-reference#getObject" rel="noopener noreferrer"&gt;&lt;code&gt;getObject&lt;/code&gt; method&lt;/a&gt; of the Minio client to download the file from the S3 bucket.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="cm"&gt;/**
 * Get file from S3 bucket
 * @param bucketName name of the bucket
 * @param fileName name of the file
 * @returns file from S3
 */&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;getFileFromBucket&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;bucketName&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;fileName&lt;/span&gt; &lt;span class="p"&gt;}:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nl"&gt;bucketName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nl"&gt;fileName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;s3Client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;statObject&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;bucketName&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;fileName&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;s3Client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getObject&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;bucketName&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;fileName&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  2. Create an API route to download files
&lt;/h4&gt;

&lt;p&gt;To download files, we will create an API route to handle file downloads. Create a file &lt;code&gt;[id].ts&lt;/code&gt; in the &lt;code&gt;pages/api/files/download/&lt;/code&gt; folder. This file will download the file from S3 and return it to the user.&lt;/p&gt;

&lt;p&gt;Here we use a dynamic route of Next.js with [id] to get the file id from the request query. More information about dynamic routes can be found in the &lt;a href="https://nextjs.org/docs/routing/dynamic-routes" rel="noopener noreferrer"&gt;Next.js docs&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The algorithm for downloading files from the server is as follows:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Get the file name and original name from the database using Prisma &lt;code&gt;file.findUnique&lt;/code&gt; method.&lt;/li&gt;
&lt;li&gt;Get the file from the S3 bucket using the &lt;code&gt;getFileFromBucket&lt;/code&gt; function.&lt;/li&gt;
&lt;li&gt;Set the header for downloading the file.&lt;/li&gt;
&lt;li&gt;Pipe the file to the response object.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;NextApiRequest&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;NextApiResponse&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;next&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;getFileFromBucket&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;~/utils/s3-file-management&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;env&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;~/env&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;db&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;~/server/db&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;handler&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;NextApiRequest&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;NextApiResponse&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;id&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;query&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;typeof&lt;/span&gt; &lt;span class="nx"&gt;id&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;string&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;status&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;400&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;message&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Invalid request&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;

  &lt;span class="c1"&gt;// get the file name and original name from the database&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;fileObject&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;file&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;findUnique&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;where&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="na"&gt;select&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;fileName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;originalName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;})&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;fileObject&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;status&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;404&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;message&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Item not found&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="c1"&gt;// get the file from the bucket and pipe it to the response object&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;getFileFromBucket&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;bucketName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;S3_BUCKET_NAME&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;fileName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;fileObject&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;fileName&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;})&lt;/span&gt;

  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;status&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;404&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;message&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Item not found&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="c1"&gt;// set header for download file&lt;/span&gt;
  &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setHeader&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;content-disposition&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;`attachment; filename="&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;fileObject&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;originalName&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"`&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

  &lt;span class="c1"&gt;// pipe the data to the res object&lt;/span&gt;
  &lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;pipe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nx"&gt;handler&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  2.1 Upload files using presigned URLs
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ft0k95ur5asx3cn7hxoqy.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ft0k95ur5asx3cn7hxoqy.png" alt="Upload files using presigned URLs Diagram" width="800" height="407"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In the diagram above, we can see the steps involved in uploading and downloading files using presigned URLs. It is a more complex approach, but it does not use resources on the Next.js server with file uploads. The presigned URL is generated on the server and sent to the client. The client uses the presigned URL to upload the file directly to S3.&lt;/p&gt;

&lt;p&gt;To upload files:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;The user sends a POST request to the API route with the file info to upload.&lt;/li&gt;
&lt;li&gt;The API route sends requests to S3 to generate presigned URLs for each file.&lt;/li&gt;
&lt;li&gt;The S3 returns the presigned URLs to the API route.&lt;/li&gt;
&lt;li&gt;The API route sends the presigned URLs to the client.&lt;/li&gt;
&lt;li&gt;The client uploads the files directly to S3 using the presigned URLs and PUT requests.&lt;/li&gt;
&lt;li&gt;The client sends the file info to the API route to save the file info.&lt;/li&gt;
&lt;li&gt;The API route saves the file info to the database.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Frontend - Upload form logic for presigned URLs
&lt;/h3&gt;

&lt;h4&gt;
  
  
  1. Create function to send request to Next.js API route to get presigned URLs
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="cm"&gt;/**
 * Gets presigned urls for uploading files to S3
 * @param formData form data with files to upload
 * @returns
 */&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;getPresignedUrls&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;files&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;ShortFileProp&lt;/span&gt;&lt;span class="p"&gt;[])&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/api/files/upload/presignedUrl&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;method&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;POST&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Content-Type&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;application/json&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="na"&gt;body&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;files&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
  &lt;span class="p"&gt;})&lt;/span&gt;
  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;PresignedUrlProp&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  2. Create function to upload files using PUT request to S3 with presigned URL
&lt;/h4&gt;

&lt;p&gt;The function &lt;code&gt;uploadToS3&lt;/code&gt; sends a PUT request to the presigned URL to upload the file to S3.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="cm"&gt;/**
 * Uploads file to S3 directly using presigned url
 * @param presignedUrl presigned url for uploading
 * @param file  file to upload
 * @returns  response from S3
 */&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;uploadToS3&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;presignedUrl&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;PresignedUrlProp&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;file&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;File&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;presignedUrl&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;method&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;PUT&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;body&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;file&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Content-Type&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;file&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="kd"&gt;type&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Access-Control-Allow-Origin&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;*&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;})&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  3. Create function to save file info in the database
&lt;/h4&gt;

&lt;p&gt;The function &lt;code&gt;saveFileInfoInDB&lt;/code&gt; sends a POST request to the API route to save the file info in the database.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="cm"&gt;/**
 * Saves file info in DB
 * @param presignedUrls presigned urls for uploading
 * @returns
 */&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;saveFileInfoInDB&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;presignedUrls&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;PresignedUrlProp&lt;/span&gt;&lt;span class="p"&gt;[])&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/api/files/upload/saveFileInfo&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;method&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;POST&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Content-Type&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;application/json&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="na"&gt;body&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;presignedUrls&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
  &lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  4. Create a form to upload files using presigned URLs
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="cm"&gt;/**
 * Uploads files to S3 and saves file info in DB
 * @param files files to upload
 * @param presignedUrls  presigned urls for uploading
 * @param onUploadSuccess callback to execute after successful upload
 * @returns
 */&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;handleUpload&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;files&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;File&lt;/span&gt;&lt;span class="p"&gt;[],&lt;/span&gt; &lt;span class="nx"&gt;presignedUrls&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;PresignedUrlProp&lt;/span&gt;&lt;span class="p"&gt;[],&lt;/span&gt; &lt;span class="nx"&gt;onUploadSuccess&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;uploadToS3Response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;all&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nx"&gt;presignedUrls&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;presignedUrl&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;file&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;files&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;find&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;file&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;file&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="nx"&gt;presignedUrl&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;originalFileName&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;file&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;size&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="nx"&gt;presignedUrl&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;fileSize&lt;/span&gt;
      &lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;file&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;File not found&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;uploadToS3&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;presignedUrl&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;file&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;})&lt;/span&gt;
  &lt;span class="p"&gt;)&lt;/span&gt;

  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;uploadToS3Response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;some&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;status&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;alert&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Upload failed&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;saveFileInfoInDB&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;presignedUrls&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="nf"&gt;onUploadSuccess&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  5. Create a form to upload files using presigned URLs using functions from the previous steps
&lt;/h4&gt;

&lt;p&gt;Here I show a simplified version of the file, without validation, loading state, and error handling.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;useRef&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;react&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;validateFiles&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;MAX_FILE_SIZE_S3_ENDPOINT&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;handleUpload&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;getPresignedUrls&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;~/utils/fileUploadHelpers&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;UploadFilesFormUI&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./UploadFilesFormUI&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;ShortFileProp&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;~/utils/types&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;UploadFilesFormProps&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;onUploadSuccess&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;UploadFilesS3PresignedUrl&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;onUploadSuccess&lt;/span&gt; &lt;span class="p"&gt;}:&lt;/span&gt; &lt;span class="nx"&gt;UploadFilesFormProps&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;fileInputRef&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;useRef&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;HTMLInputElement&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;isLoading&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setIsLoading&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;uploadToServer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;FormEvent&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;HTMLFormElement&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;preventDefault&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="c1"&gt;// get File[] from FileList&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;files&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Object&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;values&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;fileInputRef&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;current&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;files&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="c1"&gt;// validate files&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="na"&gt;filesInfo&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;ShortFileProp&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;files&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;file&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt;
      &lt;span class="na"&gt;originalFileName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;file&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;fileSize&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;file&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;size&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;}))&lt;/span&gt;

    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;presignedUrls&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;getPresignedUrls&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;filesInfo&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c1"&gt;// upload files to s3 endpoint directly and save file info to db&lt;/span&gt;
    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;handleUpload&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;files&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;presignedUrls&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;onUploadSuccess&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="nf"&gt;setIsLoading&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;UploadFilesFormUI&lt;/span&gt;
      &lt;span class="na"&gt;isLoading&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;isLoading&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
      &lt;span class="na"&gt;fileInputRef&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;fileInputRef&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
      &lt;span class="na"&gt;uploadToServer&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;uploadToServer&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
      &lt;span class="na"&gt;maxFileSize&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;MAX_FILE_SIZE_S3_ENDPOINT&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Backend - Upload files using presigned URLs
&lt;/h3&gt;

&lt;h4&gt;
  
  
  1. Create helper function to generate presigned URLs for uploading files to S3
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="cm"&gt;/**
 * Generate presigned urls for uploading files to S3
 * @param files files to upload
 * @returns promise with array of presigned urls
 */&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;createPresignedUrlToUpload&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="nx"&gt;bucketName&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;fileName&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;expiry&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;60&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;60&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;// 1 hour&lt;/span&gt;
&lt;span class="p"&gt;}:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;bucketName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;
  &lt;span class="nx"&gt;fileName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;
  &lt;span class="nx"&gt;expiry&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// Create bucket if it doesn't exist&lt;/span&gt;
  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;createBucketIfNotExists&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;bucketName&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;s3Client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;presignedPutObject&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;bucketName&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;fileName&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;expiry&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  2. Create an API route to send requests to S3 to generate presigned URLs for each file
&lt;/h4&gt;

&lt;p&gt;In this approach, we do not use formidable to parse the incoming request, so we do not need to disable the built-in body parser of Next.js. We can use the default body parser.&lt;/p&gt;

&lt;p&gt;The algorithm for generating presigned URLs for uploading files to S3:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Get the files info from the request body.&lt;/li&gt;
&lt;li&gt;Check if there are files to upload.&lt;/li&gt;
&lt;li&gt;Create an empty array to store the presigned URLs.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For each file:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Generate a unique file name using the nanoid library.&lt;/li&gt;
&lt;li&gt;Get the presigned URL using the &lt;code&gt;createPresignedUrlToUpload&lt;/code&gt; function.&lt;/li&gt;
&lt;li&gt;Add the presigned URL to the array.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Then return the array of presigned URLs in the response to the client.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;NextApiRequest&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;NextApiResponse&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;next&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;ShortFileProp&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;PresignedUrlProp&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;~/utils/types&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;createPresignedUrlToUpload&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;~/utils/s3-file-management&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;env&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;~/env&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;nanoid&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;nanoid&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;bucketName&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;S3_BUCKET_NAME&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;expiry&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;60&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;60&lt;/span&gt; &lt;span class="c1"&gt;// 24 hours&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;handler&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;NextApiRequest&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;NextApiResponse&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;method&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;POST&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;status&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;405&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;message&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Only POST requests are allowed&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="c1"&gt;// get the files from the request body&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;files&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;ShortFileProp&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;

  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;files&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;status&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;400&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;message&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;No files to upload&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;presignedUrls&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;PresignedUrlProp&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;

  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;files&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// use Promise.all to get all the presigned urls in parallel&lt;/span&gt;
    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;all&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="c1"&gt;// loop through the files&lt;/span&gt;
      &lt;span class="nx"&gt;files&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;file&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;fileName&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nf"&gt;nanoid&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;)}&lt;/span&gt;&lt;span class="s2"&gt;-&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;file&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;originalFileName&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;

        &lt;span class="c1"&gt;// get presigned url using s3 sdk&lt;/span&gt;
        &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;url&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;createPresignedUrlToUpload&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
          &lt;span class="nx"&gt;bucketName&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="nx"&gt;fileName&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="nx"&gt;expiry&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;})&lt;/span&gt;
        &lt;span class="c1"&gt;// add presigned url to the list&lt;/span&gt;
        &lt;span class="nx"&gt;presignedUrls&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
          &lt;span class="na"&gt;fileNameInBucket&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;fileName&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="na"&gt;originalFileName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;file&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;originalFileName&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="na"&gt;fileSize&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;file&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;fileSize&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;})&lt;/span&gt;
      &lt;span class="p"&gt;})&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;status&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;presignedUrls&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  3. Create an API route to save file info in the database with Prisma
&lt;/h4&gt;

&lt;p&gt;The algorithm for saving file info in the database:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Get the file info from the request body.&lt;/li&gt;
&lt;li&gt;Save the file info to the database using the Prisma &lt;code&gt;file.create&lt;/code&gt; method.&lt;/li&gt;
&lt;li&gt;Return the status and message in the response to the client.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;NextApiRequest&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;NextApiResponse&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;next&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;env&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;~/env&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;db&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;~/server/db&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;PresignedUrlProp&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;FileInDBProp&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;~/utils/types&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;handler&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;NextApiRequest&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;NextApiResponse&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;method&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;POST&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;status&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;405&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;message&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Only POST requests are allowed&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;presignedUrls&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;PresignedUrlProp&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;

  &lt;span class="c1"&gt;// Get the file name in bucket from the database&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;saveFilesInfo&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;file&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createMany&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;presignedUrls&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="na"&gt;file&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;FileInDBProp&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt;
      &lt;span class="na"&gt;bucket&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;S3_BUCKET_NAME&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;fileName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;file&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;fileNameInBucket&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;originalName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;file&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;originalFileName&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;size&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;file&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;fileSize&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;})),&lt;/span&gt;
  &lt;span class="p"&gt;})&lt;/span&gt;

  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;saveFilesInfo&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;status&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;message&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Files saved successfully&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;status&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;404&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;message&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Files not found&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  2.2 Download files using presigned URLs
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fenmnv1wc7e1w74du7nx3.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fenmnv1wc7e1w74du7nx3.png" alt="Download files using presigned URLs Diagram" width="800" height="352"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;To download files:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;The user sends a GET request with file id to the API route to get file.&lt;/li&gt;
&lt;li&gt;The API route sends a request to the database to get the file name and receives the file name.&lt;/li&gt;
&lt;li&gt;The API route sends a request to S3 to generate a presigned URL for the file and receives the presigned URL.&lt;/li&gt;
&lt;li&gt;The API route sends the presigned URL to the client.&lt;/li&gt;
&lt;li&gt;The client downloads the file directly from S3 using the presigned URL.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Frontend - Download files using presigned URLs
&lt;/h3&gt;

&lt;p&gt;To download files, we will create a function &lt;code&gt;downloadFile&lt;/code&gt; inside of the FileItem component. The function sends a GET request to the API route to get the presigned URL for the file from S3. The file is returned to the user from the API route.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;getPresignedUrl&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;file&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;FileProps&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`/api/files/download/presignedUrl/&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;file&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;downloadFile&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;file&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;FileProps&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;presignedUrl&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;getPresignedUrl&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;file&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;presignedUrl&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;_blank&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Backend - Download files using presigned URLs
&lt;/h3&gt;

&lt;h4&gt;
  
  
  1. Create helper function to generate presigned URLs for downloading files from S3
&lt;/h4&gt;

&lt;p&gt;To download files from S3, we will create a utility function &lt;code&gt;createPresignedUrlToDownload&lt;/code&gt; that uses the &lt;a href="https://min.io/docs/minio/javascript-client-api-reference#presignedGetObject" rel="noopener noreferrer"&gt;&lt;code&gt;presignedGetObject&lt;/code&gt; method&lt;/a&gt; of the Minio client to generate a presigned URL for the file.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;createPresignedUrlToDownload&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="nx"&gt;bucketName&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;fileName&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;expiry&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;60&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;60&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;// 1 hour&lt;/span&gt;
&lt;span class="p"&gt;}:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;bucketName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;
  &lt;span class="nx"&gt;fileName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;
  &lt;span class="nx"&gt;expiry&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;s3Client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;presignedGetObject&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;bucketName&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;fileName&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;expiry&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  2. Create an API route to send requests to S3 to generate presigned URLs for each file
&lt;/h4&gt;

&lt;p&gt;The algorithm for generating presigned URLs for downloading files from S3:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Get the file name from the database using the file id.&lt;/li&gt;
&lt;li&gt;Get the presigned URL using the &lt;code&gt;createPresignedUrlToDownload&lt;/code&gt; function.&lt;/li&gt;
&lt;li&gt;Return the presigned URL in the response to the client.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;NextApiRequest&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;NextApiResponse&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;next&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;createPresignedUrlToDownload&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;~/utils/s3-file-management&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;db&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;~/server/db&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;env&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;~/env&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="cm"&gt;/**
 * This route is used to get presigned url for downloading file from S3
 */&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;handler&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;NextApiRequest&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;NextApiResponse&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;method&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;GET&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;status&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;405&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;message&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Only GET requests are allowed&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;id&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;query&lt;/span&gt;

  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="k"&gt;typeof&lt;/span&gt; &lt;span class="nx"&gt;id&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;string&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;status&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;400&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;message&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Missing or invalid id&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="c1"&gt;// Get the file name in bucket from the database&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;fileObject&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;file&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;findUnique&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;where&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="na"&gt;select&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;fileName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;})&lt;/span&gt;

  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;fileObject&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;status&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;404&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;message&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Item not found&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="c1"&gt;// Get presigned url from s3 storage&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;presignedUrl&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;createPresignedUrlToDownload&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;bucketName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;S3_BUCKET_NAME&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;fileName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;fileObject&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;fileName&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;})&lt;/span&gt;

  &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;status&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;presignedUrl&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  3. Delete files from S3
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkdlvdie7htrjcwshqr45.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkdlvdie7htrjcwshqr45.png" alt="Delete files from S3 Diagram" width="800" height="445"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Frontend - Delete files from S3
&lt;/h3&gt;

&lt;p&gt;File deletion can be done using a DELETE request to the API route. I created a delete function in FileItem component, which sends a DELETE request to the API route to delete the file from the S3 bucket and the database.&lt;/p&gt;

&lt;p&gt;The algorithm for deleting files from S3:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Remove the file from the list of files on the client immediately.&lt;/li&gt;
&lt;li&gt;Send a DELETE request to the API route to delete the file from the S3 bucket and the database.&lt;/li&gt;
&lt;li&gt;Fetch the files after deleting.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Here is an example of the delete function in the FileItem component:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;deleteFile&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// remove file from the list of files on the client&lt;/span&gt;
  &lt;span class="nf"&gt;setFiles&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;files&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;FileProps&lt;/span&gt;&lt;span class="p"&gt;[])&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;
    &lt;span class="nx"&gt;files&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;file&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;FileProps&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;file&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="nx"&gt;id&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;file&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;isDeleting&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;file&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
  &lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// delete file request to the server&lt;/span&gt;
    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`/api/files/delete/&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;method&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;DELETE&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;})&lt;/span&gt;
    &lt;span class="c1"&gt;// fetch files after deleting&lt;/span&gt;
    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;fetchFiles&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nf"&gt;alert&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Failed to delete file&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;finally&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// remove isDeleting flag from the file&lt;/span&gt;
    &lt;span class="nf"&gt;setFiles&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="na"&gt;files&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;FileProps&lt;/span&gt;&lt;span class="p"&gt;[])&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;
      &lt;span class="nx"&gt;files&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="na"&gt;file&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;FileProps&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;file&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="nx"&gt;id&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;file&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;isDeleting&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;file&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Backend - Delete files from S3
&lt;/h3&gt;

&lt;h4&gt;
  
  
  1. Create a utility function to delete files from S3
&lt;/h4&gt;

&lt;p&gt;To delete files from S3, we will create a utility function &lt;code&gt;deleteFileFromBucket&lt;/code&gt; that uses the &lt;a href="https://min.io/docs/minio/linux/developers/javascript/API.html#removeobject-bucketname-objectname-removeopts-callback" rel="noopener noreferrer"&gt;&lt;code&gt;removeObject&lt;/code&gt; method&lt;/a&gt; of the Minio client to delete the file from the S3 bucket.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="cm"&gt;/**
 * Delete file from S3 bucket
 * @param bucketName name of the bucket
 * @param fileName name of the file
 * @returns true if file was deleted, false if not
 */&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;deleteFileFromBucket&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;bucketName&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;fileName&lt;/span&gt; &lt;span class="p"&gt;}:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nl"&gt;bucketName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nl"&gt;fileName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;s3Client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;removeObject&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;bucketName&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;fileName&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  2. Create an API route to delete files from S3
&lt;/h4&gt;

&lt;p&gt;Here is an example of an API route to delete files from S3. Create a file &lt;code&gt;delete/[id].ts&lt;/code&gt; in the &lt;code&gt;pages/api/files/delete&lt;/code&gt; folder. This file will delete the file from the S3 bucket and the database.&lt;/p&gt;

&lt;p&gt;The algorithm for deleting files from S3:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Get the file name in the bucket from the database using the file id.&lt;/li&gt;
&lt;li&gt;Check if the file exists in the database.&lt;/li&gt;
&lt;li&gt;Delete the file from the S3 bucket using the &lt;code&gt;deleteFileFromBucket&lt;/code&gt; function.&lt;/li&gt;
&lt;li&gt;Delete the file from the database using the Prisma &lt;code&gt;file.delete&lt;/code&gt; method.&lt;/li&gt;
&lt;li&gt;Return the status and message in the response to the client.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;NextApiRequest&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;NextApiResponse&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;next&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;deleteFileFromBucket&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;~/utils/s3-file-management&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;db&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;~/server/db&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;env&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;~/env&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;handler&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;NextApiRequest&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;NextApiResponse&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;method&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;DELETE&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;status&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;405&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;message&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Only DELETE requests are allowed&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;id&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;query&lt;/span&gt;

  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="k"&gt;typeof&lt;/span&gt; &lt;span class="nx"&gt;id&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;string&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;status&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;400&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;message&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Missing or invalid id&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="c1"&gt;// Get the file name in bucket from the database&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;fileObject&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;file&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;findUnique&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;where&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="na"&gt;select&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;fileName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;})&lt;/span&gt;

  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;fileObject&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;status&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;404&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;message&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Item not found&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="c1"&gt;// Delete the file from the bucket&lt;/span&gt;
  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;deleteFileFromBucket&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;bucketName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;S3_BUCKET_NAME&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;fileName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;fileObject&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;fileName&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;})&lt;/span&gt;
  &lt;span class="c1"&gt;// Delete the file from the database&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;deletedItem&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;file&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;delete&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;where&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;})&lt;/span&gt;

  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;deletedItem&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;status&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;message&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Item deleted successfully&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;status&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;404&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;message&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Item not found&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Deploy locally using Docker Compose
&lt;/h2&gt;

&lt;p&gt;To deploy the application locally, we will use Docker Compose to run the Next.js app, PostgreSQL, and MinIO S3. I explained how to set up the Docker Compose file in the &lt;a href="https://blog.alexefimenko.com/posts/nextjs-postgres-s3-locally" rel="noopener noreferrer"&gt;previous article&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Here I want to mention some changes to the Docker Compose file we need to make because we need to use presigned URLs.&lt;/p&gt;

&lt;p&gt;The key point is - when presigned url is created inside the docker container, it will have the same host as we set in the docker compose file. For example, if we have &lt;code&gt;environment: - S3_ENDPOINT=minio&lt;/code&gt; in the docker compose file, the presigned url will have the host &lt;code&gt;minio&lt;/code&gt;. All presigned urls will be like &lt;code&gt;http://minio:9000/bucket-name/file-name&lt;/code&gt;.&lt;br&gt;
These urls will not work on the client side (if we do not add minio to the hosts file). Here we cannot use localhost either, because localhost will be the host of the container, not the host of the client.&lt;/p&gt;

&lt;p&gt;The solution is to use the &lt;code&gt;kubernetes.docker.internal&lt;/code&gt; as the Minio S3 endpoint. This is a special DNS name that resolves to the host machine from inside a Docker container. It is available on Docker for Mac and Docker for Windows.&lt;/p&gt;

&lt;p&gt;Also make sure that &lt;code&gt;kubernetes.docker.internal&lt;/code&gt; is in the hosts file (it should be there by default). Then the presigned urls will be like &lt;code&gt;http://kubernetes.docker.internal:9000/bucket-name/file-name&lt;/code&gt; and will work on the client side.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fpud1cojgtkjyrmyh3s9v.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fpud1cojgtkjyrmyh3s9v.png" alt="Hosts file example" width="800" height="128"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Here is the full Docker Compose file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;3.9'&lt;/span&gt;
&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;nextjs-postgres-s3minio&lt;/span&gt;
&lt;span class="na"&gt;services&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;web&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;container_name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;nextjs&lt;/span&gt;
    &lt;span class="na"&gt;build&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;context&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;../&lt;/span&gt;
      &lt;span class="na"&gt;dockerfile&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;compose/web.Dockerfile&lt;/span&gt;
      &lt;span class="na"&gt;args&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;NEXT_PUBLIC_CLIENTVAR&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;clientvar'&lt;/span&gt;
    &lt;span class="na"&gt;ports&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;3000:3000&lt;/span&gt;
    &lt;span class="na"&gt;volumes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;../:/app&lt;/span&gt;
    &lt;span class="na"&gt;environment&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;DATABASE_URL=postgresql://postgres:postgres@db:5432/myapp-db?schema=public&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;S3_ENDPOINT=kubernetes.docker.internal&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;S3_PORT=9000&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;S3_ACCESS_KEY=minio&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;S3_SECRET_KEY=miniosecret&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;S3_BUCKET_NAME=s3bucket&lt;/span&gt;
    &lt;span class="na"&gt;depends_on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;db&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;minio&lt;/span&gt;
    &lt;span class="c1"&gt;# Optional, if you want to apply db schema from prisma to postgres&lt;/span&gt;
    &lt;span class="na"&gt;command&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;sh ./compose/db-push-and-start.sh&lt;/span&gt;
  &lt;span class="na"&gt;db&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;postgres:15.3&lt;/span&gt;
    &lt;span class="na"&gt;container_name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;postgres&lt;/span&gt;
    &lt;span class="na"&gt;ports&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;5432:5432&lt;/span&gt;
    &lt;span class="na"&gt;environment&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;POSTGRES_USER&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;postgres&lt;/span&gt;
      &lt;span class="na"&gt;POSTGRES_PASSWORD&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;postgres&lt;/span&gt;
      &lt;span class="na"&gt;POSTGRES_DB&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;myapp-db&lt;/span&gt;
    &lt;span class="na"&gt;volumes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;postgres-data:/var/lib/postgresql/data&lt;/span&gt;
    &lt;span class="na"&gt;restart&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;unless-stopped&lt;/span&gt;
  &lt;span class="na"&gt;minio&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;container_name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;s3minio&lt;/span&gt;
    &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;bitnami/minio:latest&lt;/span&gt;
    &lt;span class="na"&gt;ports&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;9000:9000'&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;9001:9001'&lt;/span&gt;
    &lt;span class="na"&gt;volumes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;minio_storage:/data&lt;/span&gt;
&lt;span class="na"&gt;volumes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;postgres-data&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;minio_storage&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To run the application, use the following command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker-compose &lt;span class="nt"&gt;-f&lt;/span&gt; compose/docker-compose.yml &lt;span class="nt"&gt;--env-file&lt;/span&gt; .env up
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After you run the application, you can access it at &lt;code&gt;http://localhost:3000&lt;/code&gt;.&lt;br&gt;
The Minio S3 will be available at &lt;code&gt;http://localhost:9000&lt;/code&gt;. You can use the access key &lt;code&gt;minio&lt;/code&gt; and the secret key &lt;code&gt;miniosecret&lt;/code&gt; to log in.&lt;/p&gt;

&lt;p&gt;The next step would be to deploy the application to a cloud provider. I will cover this in the next article.&lt;/p&gt;

&lt;p&gt;You can check the live demo of the application &lt;a href="http://89.111.169.67" rel="noopener noreferrer"&gt;here&lt;/a&gt;. It is shared with the public, so all files are visible to everyone. You can upload, download, and delete any files. Please do not upload any sensitive information.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;In this article, we learned how to upload and download files using Next.js, PostgreSQL, and Minio S3. We also learned how to use presigned URLs to upload and download files directly from the client to S3. We created an application to upload, download, and delete files from S3 using presigned URLs. We also learned how to deploy the application locally using Docker Compose.&lt;/p&gt;

&lt;p&gt;Hope you found this article helpful. If you have any questions or suggestions, feel free to leave a comment.&lt;/p&gt;

&lt;h3&gt;
  
  
  References and Further Reading
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://excalidraw.com/#json=yxJaRLLQlSAwKPuK3va91,UJ-_cqop7_cUyPCs7foc_w" rel="noopener noreferrer"&gt;Diagrams created with Excalidraw&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://blog.min.io/from-docker-to-localhost/" rel="noopener noreferrer"&gt;Network configuration for localhost in Docker for Minio&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://devpress.csdn.net/react/62eb6bd020df032da732b2ea.html" rel="noopener noreferrer"&gt;Upload files with NextJS + Fetch + Api routes + Typescript&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://docs.min.io/docs/javascript-client-api-reference.html" rel="noopener noreferrer"&gt;Minio Docs&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;I'm always open to making new connections! Feel free to connect with me on &lt;a href="https://www.linkedin.com/in/aleksandr-efimenko/" rel="noopener noreferrer"&gt;LinkedIn&lt;/a&gt;&lt;/p&gt;

</description>
      <category>nextjs</category>
      <category>docker</category>
      <category>webdev</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Building a Local Development Environment: Running a Next.js Full-Stack App with PostgreSQL and Minio S3 Using Docker</title>
      <dc:creator>Alex</dc:creator>
      <pubDate>Sat, 06 Jan 2024 22:37:13 +0000</pubDate>
      <link>https://dev.to/alexefimenko/building-a-local-development-environment-running-a-nextjs-full-stack-app-with-postgresql-and-minio-s3-using-docker-1e6m</link>
      <guid>https://dev.to/alexefimenko/building-a-local-development-environment-running-a-nextjs-full-stack-app-with-postgresql-and-minio-s3-using-docker-1e6m</guid>
      <description>&lt;h2&gt;
  
  
  Table of Contents
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Introduction&lt;/li&gt;
&lt;li&gt;Prerequisites&lt;/li&gt;
&lt;li&gt;
Building a local development environment

&lt;ul&gt;
&lt;li&gt;1. Create a Next.js application&lt;/li&gt;
&lt;li&gt;2. Configure Next.js to work with Docker&lt;/li&gt;
&lt;li&gt;3. Add .dockerignore file&lt;/li&gt;
&lt;li&gt;4. Configure Prisma to work with Docker&lt;/li&gt;
&lt;li&gt;5. Create a Dockerfile for the Next.js application&lt;/li&gt;
&lt;li&gt;6. Create a docker-compose.yml file&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;Run the application&lt;/li&gt;

&lt;li&gt;Conclusion&lt;/li&gt;

&lt;li&gt;References and further reading&lt;/li&gt;

&lt;/ul&gt;

&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;As a developer working on a full-stack application, you need to have a local development environment that is as close as possible to the production environment. It will allow you to test and debug your application locally before deploying it to production.&lt;/p&gt;

&lt;p&gt;Almost every full-stack application needs a database and a file storage so let's build a basic full-stack application that can save and retrieve data from a database and upload and download files from a file storage.&lt;/p&gt;

&lt;p&gt;You can run your own PostgreSQL and Minio S3 server locally, or even use a cloud service like AWS RDS and S3. But it will take some time to set up and configure. Using docker-compose will make it super easy to set up a local development environment for your full-stack application. After you test it locally, all you need to switch to the production environment is to change the environment variables.&lt;/p&gt;

&lt;p&gt;Additionally, you can test your application end-to-end (for example, using Cypress) in a local environment that is as close as possible to the production environment. Having pre-configured docker-compose file will make it easy to set up a CI/CD pipeline like GitHub Actions or GitLab CI.&lt;/p&gt;

&lt;p&gt;Once you have a docker-compose file, you and your team can use it to set up the same local development environment on any machine in a few minutes with just one command. Overall, it will save you a lot of time and make your life easier.&lt;/p&gt;

&lt;p&gt;In this article, we will look at how to build a local development environment for a full-stack Next.js application with Prisma ORM connected to PostgreSQL as a database and Minio S3 as a file storage using Docker-Compose.&lt;/p&gt;

&lt;p&gt;You can find the full source code for this tutorial on &lt;a href="https://github.com/aleksandr-efimenko/local-nextjs-postgres-s3" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;When you are ready to deploy your application to production, you can use any type of database:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Supabase (I love this one)&lt;/li&gt;
&lt;li&gt;Vercel Postgres&lt;/li&gt;
&lt;li&gt;AWS RDS&lt;/li&gt;
&lt;li&gt;Google Cloud SQL&lt;/li&gt;
&lt;li&gt;Azure Database for PostgreSQL&lt;/li&gt;
&lt;li&gt;Heroku Postgres&lt;/li&gt;
&lt;li&gt;DigitalOcean Managed Databases&lt;/li&gt;
&lt;li&gt;ScaleGrid&lt;/li&gt;
&lt;li&gt;...&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The same goes for the file storage, you need one that is compatible with the S3 protocol:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;AWS S3&lt;/li&gt;
&lt;li&gt;Google Cloud Storage (I tested it, it works)&lt;/li&gt;
&lt;li&gt;Wasabi (One of the cheapest options)&lt;/li&gt;
&lt;li&gt;Backblaze B2&lt;/li&gt;
&lt;li&gt;DigitalOcean Spaces&lt;/li&gt;
&lt;li&gt;...&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Prerequisites
&lt;/h2&gt;

&lt;p&gt;To follow this tutorial, you need to have Docker and Docker-Compose installed on your machine. You can find the instructions on how to install &lt;a href="https://docs.docker.com/get-docker/" rel="noopener noreferrer"&gt;Docker&lt;/a&gt; and &lt;a href="https://docs.docker.com/compose/install/" rel="noopener noreferrer"&gt;Docker-Compose&lt;/a&gt; on the official Docker website.&lt;/p&gt;

&lt;p&gt;When I firstly faced the task of setting up a local development environment for Next.js, Prisma and PostgreSQL, I tried to use &lt;a href="https://create.t3.gg/en/deployment/docker" rel="noopener noreferrer"&gt;T3 Docker tutorial&lt;/a&gt; but it didn't work for me. However, I use it as a starting point for this tutorial.&lt;/p&gt;

&lt;h2&gt;
  
  
  Building a local development environment
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. Create a Next.js application
&lt;/h3&gt;

&lt;p&gt;Let's start by creating a Next.js application. We will use the T3 stack (TypeScript, TailwindCSS, and Prisma ORM) for this tutorial to skip installing and configuring all the dependencies which is out of the scope of this article. You can find more information about the &lt;a href="https://create.t3.gg/" rel="noopener noreferrer"&gt;T3 stack&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Run the following command to create a new Next.js:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm create t3-app@latest
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After you run the command, you will be asked several questions:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;   ___ ___ ___   __ _____ ___   _____ ____    __   ___ ___
  / __| _ &lt;span class="se"&gt;\ &lt;/span&gt;__| /  &lt;span class="se"&gt;\_&lt;/span&gt;   _| __| |_   _|__ /   /  &lt;span class="se"&gt;\ &lt;/span&gt;| _ &lt;span class="se"&gt;\ &lt;/span&gt;_ &lt;span class="se"&gt;\&lt;/span&gt;
 | &lt;span class="o"&gt;(&lt;/span&gt;__|   / _| / /&lt;span class="se"&gt;\ \|&lt;/span&gt; | | _|    | |  |_ &lt;span class="se"&gt;\ &lt;/span&gt; / /&lt;span class="se"&gt;\ \|&lt;/span&gt;  _/  _/
  &lt;span class="se"&gt;\_&lt;/span&gt;__|_|_&lt;span class="se"&gt;\_&lt;/span&gt;__|_/‾‾&lt;span class="se"&gt;\_\_&lt;/span&gt;| |___|   |_| |___/ /_/‾‾&lt;span class="se"&gt;\_\_&lt;/span&gt;| |_|

◇  What will your project be called?
│  local-nextjs-postgres-s3
│
◇  Will you be using TypeScript or JavaScript?
│  TypeScript
│
◇  Will you be using Tailwind CSS &lt;span class="k"&gt;for &lt;/span&gt;styling?
│  Yes
│
◇  Would you like to use tRPC?
│  No
│
◇  What authentication provider would you like to use?
│  None
│
◇  What database ORM would you like to use?
│  Prisma
│
◇   EXPERIMENTAL  Would you like to use Next.js App Router?
│  No
│
◇  Should we initialize a Git repository and stage the changes?
│  Yes
│
◇  Should we run &lt;span class="s1"&gt;'npm install'&lt;/span&gt; &lt;span class="k"&gt;for &lt;/span&gt;you?
│  Yes
│
◇  What import &lt;span class="nb"&gt;alias &lt;/span&gt;would you like to use?
│  ~/
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  2. Configure Next.js to work with Docker
&lt;/h3&gt;

&lt;p&gt;According to the &lt;a href="https://nextjs.org/docs/pages/api-reference/next-config-js/output" rel="noopener noreferrer"&gt;Next.js documentation&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Next.js can automatically create a standalone folder that copies only the necessary files for a production deployment including select files in node_modules.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;To reduce image size we need to add &lt;code&gt;output: "standalone"&lt;/code&gt; in the next.config.js file.&lt;br&gt;
The next.config.js file should look like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;config&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;reactStrictMode&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;output&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;standalone&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="c1"&gt;// ...&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  3. Add .dockerignore file
&lt;/h3&gt;

&lt;p&gt;I prefer having a separate folder for the docker files, so I created a folder called &lt;code&gt;compose&lt;/code&gt; in the root of the project. We need to add a &lt;code&gt;.dockerignore&lt;/code&gt; file to this folder to exclude unnecessary files from the Docker image. The &lt;code&gt;.dockerignore&lt;/code&gt; file should look like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;.env
Dockerfile
.dockerignore
.next
.git
.gitignore
node_modules
npm-debug.log
README.md
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  4. Configure Prisma to work with Docker
&lt;/h3&gt;

&lt;p&gt;In the &lt;code&gt;prisma/schema.prisma&lt;/code&gt; file, we need to&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Change the provider from &lt;code&gt;sqlite&lt;/code&gt; to &lt;code&gt;postgresql&lt;/code&gt;:&lt;/li&gt;
&lt;li&gt;Add &lt;code&gt;binaryTargets&lt;/code&gt; to the generator block. It will allow us to use the Prisma CLI inside the Docker container. You need to your &lt;code&gt;binaryTargets&lt;/code&gt; specific to your OS and architecture. For example, for M1 Mac, I use &lt;code&gt;"linux-musl-arm64-openssl-3.0.x"&lt;/code&gt;. To support other OS and architectures, you need to add them to the &lt;code&gt;binaryTargets&lt;/code&gt; array. More about binaryTargets in the &lt;a href="https://www.prisma.io/docs/orm/reference/prisma-schema-reference#binarytargets-options" rel="noopener noreferrer"&gt;Prisma documentation&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I want to use the same &lt;code&gt;schema.prisma&lt;/code&gt; file for local development on machines with different OS and architectures and also for CI/CD pipelines on GitHub Actions. So in my case, the &lt;code&gt;prisma/schema.prisma&lt;/code&gt; file looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;generator client {
    provider      = "prisma-client-js"
    binaryTargets = ["native", "linux-musl-arm64-openssl-3.0.x", "linux-musl-openssl-3.0.x", "rhel-openssl-1.0.x"]
}

datasource db {
  provider = "postgresql"
  url      = env("DATABASE_URL")
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  5. Create a Dockerfile for the Next.js application
&lt;/h3&gt;

&lt;p&gt;Inside the &lt;code&gt;compose&lt;/code&gt; folder, create a file called &lt;code&gt;web.Dockerfile&lt;/code&gt; with the following content:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight docker"&gt;&lt;code&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="s"&gt; node:18-alpine&lt;/span&gt;

&lt;span class="k"&gt;RUN &lt;/span&gt;&lt;span class="nb"&gt;mkdir &lt;/span&gt;app
&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; ../prisma  ./app&lt;/span&gt;
&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; ../package.json ../package-lock.json ./app&lt;/span&gt;
&lt;span class="k"&gt;WORKDIR&lt;/span&gt;&lt;span class="s"&gt; /app&lt;/span&gt;

&lt;span class="k"&gt;RUN &lt;/span&gt;npm ci

&lt;span class="k"&gt;CMD&lt;/span&gt;&lt;span class="s"&gt; ["npm", "run", "dev"]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We will use the &lt;code&gt;node:18-alpine&lt;/code&gt; image as a base image. It is a lightweight image that contains Node.js 18 and npm. We will copy the &lt;code&gt;/prisma&lt;/code&gt; folder, &lt;code&gt;package.json&lt;/code&gt; and &lt;code&gt;package-lock.json&lt;/code&gt; files to the &lt;code&gt;/app&lt;/code&gt; folder and run &lt;code&gt;npm ci&lt;/code&gt; to install the dependencies.&lt;/p&gt;

&lt;p&gt;Using 'clean install' (&lt;code&gt;npm ci&lt;/code&gt;) instead of 'install' (&lt;code&gt;npm i&lt;/code&gt;) is a good practice for Docker images. It will ensure that the dependencies are installed from the &lt;code&gt;package-lock.json&lt;/code&gt; file and not from the node_modules cache. This is faster than 'install', which is especially important for CI/CD pipelines where you want to keep the build time as short as possible.&lt;/p&gt;

&lt;h3&gt;
  
  
  6. Create a docker compose file
&lt;/h3&gt;

&lt;p&gt;Docker compose file is used to define and run multi-container Docker applications with a single command &lt;code&gt;docker-compose up&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Here we will not go into details about docker-compose files. In general our docker-compose file creates 3 services: web (Next.js application built with our Dockerfile), db (PostgreSQL database), and minio (Minio S3 file storage). Remember to add volumes for the database and file storage services. Otherwise, the data will be lost when you stop the containers.&lt;/p&gt;

&lt;p&gt;It is generally not recommended to store environment variables in the docker-compose file. However, in this particular scenario, for educational purposes and given that we are exclusively using it for local development and testing, it looks acceptable.&lt;br&gt;
If you do not want to store secrets in the docker-compose file, you should use a .env file and use &lt;code&gt;${VARIABLE_NAME}&lt;/code&gt; syntax to reference the variables. More about environment variables in docker-compose files &lt;a href="https://docs.docker.com/compose/compose-file/09-secrets" rel="noopener noreferrer"&gt;Docker compose file reference&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Inside the &lt;code&gt;compose&lt;/code&gt; folder, create a file called &lt;code&gt;docker-compose.yml&lt;/code&gt; with the following content:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;3.9"&lt;/span&gt;
&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;nextjs-postgres-s3minio&lt;/span&gt;
&lt;span class="na"&gt;services&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;web&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;container_name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;nextjs&lt;/span&gt;
    &lt;span class="na"&gt;build&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;context&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;../&lt;/span&gt;
      &lt;span class="na"&gt;dockerfile&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;compose/web.Dockerfile&lt;/span&gt;
      &lt;span class="na"&gt;args&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;NEXT_PUBLIC_CLIENTVAR&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;clientvar"&lt;/span&gt;
    &lt;span class="na"&gt;ports&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;3000:3000&lt;/span&gt;
    &lt;span class="na"&gt;volumes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;../:/app&lt;/span&gt;
    &lt;span class="na"&gt;environment&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;DATABASE_URL=postgresql://postgres:postgres@db:5432/myapp-db?schema=public&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;S3_ENDPOINT=minio&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;S3_PORT=9000&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;S3_ACCESS_KEY=minio&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;S3_SECRET_KEY=miniosecret&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;S3_BUCKET_NAME=s3bucket&lt;/span&gt;
    &lt;span class="na"&gt;depends_on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;db&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;minio&lt;/span&gt;
  &lt;span class="na"&gt;db&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;postgres:15.3&lt;/span&gt;
    &lt;span class="na"&gt;container_name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;postgres&lt;/span&gt;
    &lt;span class="na"&gt;ports&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;5432:5432&lt;/span&gt;
    &lt;span class="na"&gt;environment&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;POSTGRES_USER&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;postgres&lt;/span&gt;
      &lt;span class="na"&gt;POSTGRES_PASSWORD&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;postgres&lt;/span&gt;
      &lt;span class="na"&gt;POSTGRES_DB&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;myapp-db&lt;/span&gt;
    &lt;span class="na"&gt;volumes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;postgres-data:/var/lib/postgresql/data&lt;/span&gt;
    &lt;span class="na"&gt;restart&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;unless-stopped&lt;/span&gt;
  &lt;span class="na"&gt;minio&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;container_name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;s3minio&lt;/span&gt;
    &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;bitnami/minio:latest&lt;/span&gt;
    &lt;span class="na"&gt;ports&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;9000:9000"&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;9001:9001"&lt;/span&gt;
    &lt;span class="na"&gt;volumes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;minio_storage:/data&lt;/span&gt;
&lt;span class="na"&gt;volumes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;postgres-data&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;minio_storage&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Run the application
&lt;/h2&gt;

&lt;p&gt;Depending on where you have your docker-compose file located and what options you want to use,&lt;br&gt;&lt;br&gt;
you need to run the following command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# If you have docker files in the root of the project&lt;/span&gt;
docker-compose up

&lt;span class="c"&gt;# In our case, we have dockerfile and docker-compose file in the `compose` folder, so we need to run:&lt;/span&gt;
docker-compose &lt;span class="nt"&gt;-f&lt;/span&gt; compose/docker-compose.yml up

&lt;span class="c"&gt;# --- Optional ---&lt;/span&gt;
&lt;span class="c"&gt;# For running the application with secrets ${VARIABLE_NAME} stored in the .env file, we would need to run:&lt;/span&gt;
docker-compose &lt;span class="nt"&gt;-f&lt;/span&gt; compose/docker-compose.yml &lt;span class="nt"&gt;--env-file&lt;/span&gt; .env up

&lt;span class="c"&gt;# If you want to run the application in the background, you can use the -d flag:&lt;/span&gt;
docker-compose &lt;span class="nt"&gt;-f&lt;/span&gt; compose/docker-compose.yml up &lt;span class="nt"&gt;-d&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It will run build the Next.js application and run it on port 3000. It will also download the PostgreSQL and Minio S3 docker images and run them on ports 5432 and 9000 respectively.&lt;/p&gt;

&lt;p&gt;After the application is built and images are downloaded, you will see the following output:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjrbdd4scxfizsndsv2is.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjrbdd4scxfizsndsv2is.png" alt="Screenshot of docker desktop application running nextjs, postgres and minio s3 services" width="800" height="422"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You can access the application at &lt;a href="http://localhost:3000" rel="noopener noreferrer"&gt;http://localhost:3000&lt;/a&gt;, PostgreSQL database at &lt;a href="http://localhost:5432" rel="noopener noreferrer"&gt;http://localhost:5432&lt;/a&gt; (login: postgres, password: postgres), and Minio S3 at &lt;a href="http://localhost:9000" rel="noopener noreferrer"&gt;http://localhost:9000&lt;/a&gt; (login: minio, password: miniosecret).&lt;br&gt;
Credentials for the database and file storage are stored in the docker-compose file. You can change them if you want.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;In this article, we looked at how to build a local development environment for a full-stack Next.js application with Prisma ORM connected to PostgreSQL as a database and Minio S3 as a file storage using Docker-Compose.&lt;/p&gt;

&lt;h2&gt;
  
  
  References and further reading:
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://create.t3.gg/en/deployment/docker" rel="noopener noreferrer"&gt;Containerize T3 stack and deploy it as a single container using Docker&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://nextjs.org/docs/pages/building-your-application/deploying#docker-image" rel="noopener noreferrer"&gt;Next.js deployment documentation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/vercel/next.js/tree/canary/examples/with-docker" rel="noopener noreferrer"&gt;Official Next.js Docker example&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.docker.com/compose/compose-file/" rel="noopener noreferrer"&gt;Docker Compose file reference&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://shisho.dev/blog/posts/how-to-use-dockerignore" rel="noopener noreferrer"&gt;How to use .dockerignore and its importance&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.linkedin.com/pulse/securing-docker-builds-comprehensive-guide-usage-best-ilyas-ou-sbaa/" rel="noopener noreferrer"&gt;Securing Docker Builds: A Comprehensive Guide to .dockerignore Usage and Best Practices&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.prisma.io/docs/orm/reference/prisma-schema-reference#binarytargets-options" rel="noopener noreferrer"&gt;Prisma schema reference&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://hub.docker.com/r/minio/minio" rel="noopener noreferrer"&gt;Minio S3 Docker image&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;I hope you found this article useful. If you have any questions or comments, please let me know in the comments below.&lt;/p&gt;

&lt;p&gt;In the &lt;a href="https://dev.to/alexefimenko/building-a-file-storage-with-nextjs-postgresql-and-minio-s3-bla"&gt;the next article&lt;/a&gt;, we add a file upload functionality and database integration to our application.&lt;/p&gt;




&lt;p&gt;I'm always open to making new connections! Feel free to connect with me on &lt;a href="https://www.linkedin.com/in/aleksandr-efimenko" rel="noopener noreferrer"&gt;LinkedIn&lt;/a&gt;&lt;/p&gt;

</description>
      <category>nextjs</category>
      <category>webdev</category>
      <category>docker</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Implementing Debounce in React for Efficient Delayed Search Queries</title>
      <dc:creator>Alex</dc:creator>
      <pubDate>Fri, 05 Jan 2024 01:21:56 +0000</pubDate>
      <link>https://dev.to/alexefimenko/implementing-debounce-in-react-for-efficient-delayed-search-queries-4m49</link>
      <guid>https://dev.to/alexefimenko/implementing-debounce-in-react-for-efficient-delayed-search-queries-4m49</guid>
      <description>&lt;p&gt;In this article, we will look at how to implement debounce in React for efficient delayed search queries. The problem we are trying to solve is that we want to make an API call to search for a user after the user has stopped typing for 1s (in real life, it would be more like 300ms). It will make the API calls more efficient and reduce the load on the server.&lt;/p&gt;

&lt;p&gt;We will use the debounce function from my previous article &lt;a href="https://dev.to/alexefimenko/lets-implement-a-debounce-function-in-javascript-1ij1"&gt;Let’s implement a Debounce function in Javascript&lt;/a&gt;. But we will need to adjust it a bit to use it in a React component.&lt;/p&gt;

&lt;p&gt;You can check how it works in the CodeSandbox below:&lt;/p&gt;

&lt;p&gt;&lt;iframe src="https://codesandbox.io/embed/jw28mj"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;The main problem to use the debounce function in React is that we need to store the timer ID between renders. If we just use a useState hook, the timer ID will be reset on every render. So for this, we will use the useRef hook as it is &lt;a href="https://react.dev/reference/react/useRef#referencing-a-value-with-a-ref" rel="noopener noreferrer"&gt;recommended by the React team&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Let's adjust the debounce function to use the useRef hook:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;debounceTimeout&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;useRef&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nb"&gt;ReturnType&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;typeof&lt;/span&gt; &lt;span class="nx"&gt;setTimeout&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;debounce&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;func&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;delay&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;function &lt;/span&gt;&lt;span class="p"&gt;(...&lt;/span&gt;&lt;span class="nx"&gt;args&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[])&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;debounceTimeout&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;current&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
     &lt;span class="nf"&gt;clearTimeout&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;debounceTimeout&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;current&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt; 
   &lt;span class="nx"&gt;debounceTimeout&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;current&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;setTimeout&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nf"&gt;func&lt;/span&gt;&lt;span class="p"&gt;(...&lt;/span&gt;&lt;span class="nx"&gt;args&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="nx"&gt;debounceTimeout&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;current&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="nx"&gt;delay&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We are going to search through a list of countries. We will use the useState hook to store the search term and the search result. We will use the debounce function to create a debounced search function that will be called after the wait time has passed:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;searchTerm&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setSearchTerm&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;""&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;searchResult&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setSearchResult&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;useState&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;([]);&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;performSearch&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;query&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;query&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;setSearchResult&lt;/span&gt;&lt;span class="p"&gt;([]);&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;countries&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;filter&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;country&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;country&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toLowerCase&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;includes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;query&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toLowerCase&lt;/span&gt;&lt;span class="p"&gt;()))&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sort&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="nf"&gt;setSearchResult&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;So the debounced search function will look like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;debouncedSearch&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;debounce&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;performSearch&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;DELAY&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We will use the debounced search function in the input change handler:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;handleInputChange&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ChangeEvent&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;HTMLInputElement&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;value&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;target&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nf"&gt;setSearchTerm&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nf"&gt;debouncedSearch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I prefer using Tailwind CSS for styling, so I added some styling to the component. &lt;/p&gt;

&lt;p&gt;
  The full code of the component
  &lt;br&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;useRef&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;react&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;countries&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./countries&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./App.css&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="c1"&gt;// set delay for debounce function in milliseconds&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;DELAY&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1000&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;App&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;searchTerm&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setSearchTerm&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;''&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;searchResult&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setSearchResult&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;useState&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;([])&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;debounceTimeout&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;useRef&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nb"&gt;ReturnType&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;typeof&lt;/span&gt; &lt;span class="nx"&gt;setTimeout&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

  &lt;span class="c1"&gt;// Search function&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;performSearch&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;query&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;query&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nf"&gt;setSearchResult&lt;/span&gt;&lt;span class="p"&gt;([])&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;countries&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;filter&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;country&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;country&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toLowerCase&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;includes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;query&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toLowerCase&lt;/span&gt;&lt;span class="p"&gt;())).&lt;/span&gt;&lt;span class="nf"&gt;sort&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="nf"&gt;setSearchResult&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="c1"&gt;// Debounce function&lt;/span&gt;
  &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;debounce&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;func&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;delay&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;function &lt;/span&gt;&lt;span class="p"&gt;(...&lt;/span&gt;&lt;span class="nx"&gt;args&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[])&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;debounceTimeout&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;current&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="nf"&gt;clearTimeout&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;debounceTimeout&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;current&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="nx"&gt;debounceTimeout&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;current&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;setTimeout&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nf"&gt;func&lt;/span&gt;&lt;span class="p"&gt;(...&lt;/span&gt;&lt;span class="nx"&gt;args&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="nx"&gt;debounceTimeout&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;current&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;
      &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="nx"&gt;delay&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="c1"&gt;// Debounced search function&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;debouncedSearch&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;debounce&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;performSearch&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;DELAY&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

  &lt;span class="c1"&gt;// Event handler for input changes&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;handleInputChange&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ChangeEvent&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;HTMLInputElement&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;value&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;target&lt;/span&gt;
    &lt;span class="nf"&gt;setSearchTerm&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nf"&gt;debouncedSearch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;delayMessage&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&amp;gt;&lt;/span&gt;
      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;p&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;Delay&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="nx"&gt;effect&lt;/span&gt; &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="nx"&gt;typing&lt;/span&gt;&lt;span class="p"&gt;...&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/p&amp;gt; &amp;lt;p&amp;gt;Search will run after 1 second of inactivity.&amp;lt;/&lt;/span&gt;&lt;span class="nx"&gt;p&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;  &lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;searchResultEmpty&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;searchResult&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
  &lt;span class="c1"&gt;// get first 20 results&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;searchResultList&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;searchResult&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;slice&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;c&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;li&lt;/span&gt; &lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;c&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;c&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/li&amp;gt;&lt;/span&gt;&lt;span class="err"&gt;)
&lt;/span&gt;  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt; &lt;span class="nx"&gt;className&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;flex flex-col gap-5&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt; &lt;span class="nx"&gt;className&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;h-12&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;debounceTimeout&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;current&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;delayMessage&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt; &lt;span class="nx"&gt;className&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;flex gap-5 items-center h-24&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;label&lt;/span&gt; &lt;span class="nx"&gt;htmlFor&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;search-input&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="nx"&gt;className&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;text-xl&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
          &lt;span class="nx"&gt;Search&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/label&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;input&lt;/span&gt;
          &lt;span class="nx"&gt;className&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;border-2 border-gray-300 rounded-md px-3 py-2 text-lg&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
          &lt;span class="kd"&gt;type&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;text&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
          &lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;search-input&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
          &lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;searchTerm&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
          &lt;span class="nx"&gt;onChange&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;handleInputChange&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
          &lt;span class="nx"&gt;placeholder&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Type to search...&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
        &lt;span class="o"&gt;/&amp;gt;&lt;/span&gt;
        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt; &lt;span class="nx"&gt;className&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;w-12&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;debounceTimeout&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;current&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;LoadingCircle&lt;/span&gt; &lt;span class="o"&gt;/&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt; &lt;span class="nx"&gt;className&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;h-64&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;{{&lt;/span&gt; &lt;span class="nx"&gt;searchResultEmpty&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;ul&lt;/span&gt; &lt;span class="nx"&gt;className&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;text-left list-disc list-inside text-lg&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;searchResultList&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/ul&amp;gt;&lt;/span&gt;&lt;span class="err"&gt;}
&lt;/span&gt;        &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;searchResultEmpty&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;searchTerm&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;debounceTimeout&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;current&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
          &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt; &lt;span class="nx"&gt;className&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;text-lg animate-pulse&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;No&lt;/span&gt; &lt;span class="nx"&gt;results&lt;/span&gt; &lt;span class="nx"&gt;found&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;        &lt;span class="p"&gt;)}&lt;/span&gt;
      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;  &lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;LoadingCircle&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;svg&lt;/span&gt;
      &lt;span class="nx"&gt;className&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;animate-spin h-12 w-12 text-gray-700&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
      &lt;span class="nx"&gt;xmlns&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;http://www.w3.org/2000/svg&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
      &lt;span class="nx"&gt;fill&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;none&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
      &lt;span class="nx"&gt;viewBox&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;0 0 24 24&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
    &lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;circle&lt;/span&gt; &lt;span class="nx"&gt;className&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;opacity-50&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="nx"&gt;cx&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;12&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="nx"&gt;cy&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;12&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="nx"&gt;r&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;10&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="nx"&gt;stroke&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;currentColor&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="nx"&gt;strokeWidth&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;4&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/circle&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;path&lt;/span&gt; &lt;span class="nx"&gt;fill&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;currentColor&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="nx"&gt;d&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4z&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/path&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/svg&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;  &lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;




&lt;/p&gt;

&lt;p&gt;You also can check my GitHub repository &lt;a href="https://github.com/aleksandr-efimenko/debounce-react-sandbox" rel="noopener noreferrer"&gt;debounce-react&lt;/a&gt; for the full code.&lt;/p&gt;

&lt;p&gt;I hope you found this article useful. If you have any questions or comments, please let me know in the comments below.&lt;/p&gt;




&lt;p&gt;I'm always open to making new connections! Feel free to connect with me on &lt;a href="https://www.linkedin.com/in/aleksandr-efimenko" rel="noopener noreferrer"&gt;LinkedIn&lt;/a&gt;&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>react</category>
      <category>typescript</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Exploring 4 Ways to Compare Objects in JavaScript with Performance Analysis</title>
      <dc:creator>Alex</dc:creator>
      <pubDate>Thu, 04 Jan 2024 00:35:35 +0000</pubDate>
      <link>https://dev.to/alexefimenko/object-and-array-comparison-in-javascript-4pef</link>
      <guid>https://dev.to/alexefimenko/object-and-array-comparison-in-javascript-4pef</guid>
      <description>&lt;h3&gt;
  
  
  Table of Contents
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Introduction&lt;/li&gt;
&lt;li&gt;
Ways to compare objects and arrays in Javascript:

&lt;ul&gt;
&lt;li&gt;1. Fast-deep-equal and other similar libraries&lt;/li&gt;
&lt;li&gt;2. Node.js assert.deepEqual() method and Node.js util.isDeepStrictEqual() method&lt;/li&gt;
&lt;li&gt;3. JSON.stringify() method&lt;/li&gt;
&lt;li&gt;4. Custom object and array comparison function&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;Performance comparison&lt;/li&gt;

&lt;/ul&gt;




&lt;h3&gt;
  
  
  Introduction
&lt;/h3&gt;

&lt;p&gt;Deep equality check is a common problem in Javascript. Unlike the regular equality operator (== or ===), which only checks for shallow equality, deep equal traverses through the entire structure of the objects or arrays to validate their equality.&lt;/p&gt;

&lt;p&gt;The problem with the regular equality operator is that it only checks references of the objects or arrays. If two objects or arrays have the same values but different references, they will not be considered equal.&lt;/p&gt;

&lt;h3&gt;
  
  
  There are several common ways to compare objects and arrays in Javascript:
&lt;/h3&gt;

&lt;h4&gt;
  
  
  1. &lt;a href="https://github.com/epoberezkin/fast-deep-equal" rel="noopener noreferrer"&gt;Fast-deep-equal&lt;/a&gt; and other similar libraries
&lt;/h4&gt;

&lt;p&gt;This library provides a function called equal() which can be used to compare objects and arrays. It is a very popular library, it has 20+ million weekly downloads on npm.&lt;/p&gt;

&lt;p&gt;This library wasn't in the first version of this article, it was &lt;a href="https://dev.to/plxel/comment/2c0lb"&gt;suggested by Aleksei Mikhailov&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The main advantage of this library is that it is very fast. It is 10-100 times faster than other libraries like Lodash's isEqual() method according to the author's benchmark tests:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Library&lt;/th&gt;
&lt;th&gt;Ops/sec&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;fast-deep-equal&lt;/td&gt;
&lt;td&gt;261,950&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;fast-equals&lt;/td&gt;
&lt;td&gt;230,957&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;fast-deep-equal/es6&lt;/td&gt;
&lt;td&gt;212,991&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;nano-equal&lt;/td&gt;
&lt;td&gt;187,995&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;shallow-equal-fuzzy&lt;/td&gt;
&lt;td&gt;138,302&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;underscore.isEqual&lt;/td&gt;
&lt;td&gt;74,423&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;util.isDeepStrictEqual&lt;/td&gt;
&lt;td&gt;46,440&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;lodash.isEqual&lt;/td&gt;
&lt;td&gt;36,637&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;deep-eql&lt;/td&gt;
&lt;td&gt;35,312&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;ramda.equals&lt;/td&gt;
&lt;td&gt;12,054&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;deep-equal&lt;/td&gt;
&lt;td&gt;2,310&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;assert.deepStrictEqual&lt;/td&gt;
&lt;td&gt;456&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;To use it, you need to install the library using npm or yarn.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install &lt;/span&gt;fast-deep-equal
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then you can import it in your code and use it.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;equal&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;fast-deep-equal&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;obj1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;a&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;b&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;obj2&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;a&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;b&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="nf"&gt;equal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;obj1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;obj2&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// true&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Other libraries:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://lodash.com/docs/4.17.15#isEqual" rel="noopener noreferrer"&gt;Lodash's isEqual&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://ramdajs.com/docs/#equals" rel="noopener noreferrer"&gt;Ramda&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://underscorejs.org/#isEqual" rel="noopener noreferrer"&gt;Underscore&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://immutable-js.com/docs/v3.8.2/is()" rel="noopener noreferrer"&gt;Immutable.js&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/planttheidea/fast-equals" rel="noopener noreferrer"&gt;Fast-equals&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;




&lt;h4&gt;
  
  
  2. &lt;a href="https://nodejs.org/api/assert.html#assert_assert_deepstrictequal_actual_expected_message" rel="noopener noreferrer"&gt;Node.js assert.deepEqual() method&lt;/a&gt; and &lt;a href="https://nodejs.org/api/util.html#util_util_isdeepstrictequal_val1_val2" rel="noopener noreferrer"&gt;Node.js util.isDeepStrictEqual() method&lt;/a&gt;
&lt;/h4&gt;

&lt;p&gt;This is a part of the Node.js assert module.&lt;/p&gt;

&lt;p&gt;The main downside of this method is that it can only be used in Node.js but not in the browser.&lt;/p&gt;

&lt;p&gt;Another issue is this function throws an error if the objects are not equal. This is not ideal if you want to use it in a conditional statement. You can use try/catch to handle the error, but it is not ideal.&lt;/p&gt;

&lt;p&gt;util.isDeepStrictEqual() is similar to assert.deepEqual() but it does not throw an error if the objects are not equal. It returns true or false depending on whether the objects are equal or not. This is more suitable for conditional statements.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;assert&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;assert&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;strict&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;obj1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;a&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;b&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;obj2&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;a&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;b&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;obj3&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;a&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;b&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="nx"&gt;assert&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;deepEqual&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;obj1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;obj2&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// true&lt;/span&gt;

&lt;span class="nx"&gt;assert&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;deepEqual&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;obj1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;obj3&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// AssertionError [ERR_ASSERTION]: Expected values to be strictly deep-equal:&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h4&gt;
  
  
  3. &lt;a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON/stringify" rel="noopener noreferrer"&gt;JSON.stringify() method&lt;/a&gt;
&lt;/h4&gt;

&lt;p&gt;This is a built-in method in Javascript. It converts a Javascript object or array into a JSON string. The JSON string can be compared using the regular equality operator. This is the most used method to compare objects and arrays in Javascript.&lt;/p&gt;

&lt;p&gt;But it has some downsides, the main issue with this method is that order of the keys in the object matters. If the order of the keys is different, the JSON string will be different even if the objects are equal. To handle this, you can sort the keys before comparing them.&lt;/p&gt;

&lt;p&gt;Another problem is when one of the objects contains an undefined value. The JSON.stringify() method will convert the undefined value to null. This will cause the comparison to fail even if the objects are equal. To handle this, you can use a custom replacer function to convert undefined values to null.&lt;/p&gt;

&lt;p&gt;One more limitation with JSON.stringify() is that it does not work if the object or array contains functions or circular references. For example, if the object contains a function, it will be converted to null. If the object contains a circular reference, it will throw an error. There are other issues with converting objects to JSON strings, you can read more about them &lt;a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON/stringify#description" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;obj1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;a&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;b&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;obj2&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;a&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;b&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;obj1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;obj2&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// true&lt;/span&gt;

&lt;span class="c1"&gt;// Order of the keys matters&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;obj3&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;b&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;a&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;obj1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;obj3&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// false&lt;/span&gt;

&lt;span class="c1"&gt;// Undefined values are converted to null&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;obj4&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;a&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;b&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;undefined&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;obj4&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// "{"a":1}"&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;obj5&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;a&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;obj5&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// "{"a":1}"&lt;/span&gt;

&lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;obj4&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;obj5&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// true&lt;/span&gt;

&lt;span class="c1"&gt;// Functions are converted to null&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;obj6&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;a&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;b&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;function &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;hello&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;obj6&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// "{"a":1}"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h4&gt;
  
  
  4. Custom object and array comparison function
&lt;/h4&gt;

&lt;p&gt;Let's implement a custom object and array comparison function. We will use recursion to implement the comparison function.&lt;/p&gt;

&lt;p&gt;I wrote this function as an &lt;a href="https://leetcode.com/problems/json-deep-equal/description/" rel="noopener noreferrer"&gt;Exercise "2628. JSON Deep Equal" from LeetCode&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="cm"&gt;/**
 * @param {null|boolean|number|string|Array|Object} o1
 * @param {null|boolean|number|string|Array|Object} o2
 * @return {boolean}
 */&lt;/span&gt;
&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;areDeeplyEqual&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;o1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;o2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// 1. Primitive values - if strictly equal, return true&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;o1&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="nx"&gt;o2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="c1"&gt;// 2. Null values - if either object is null, they are not equal&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;o1&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nx"&gt;o2&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="c1"&gt;// 4. If not object, compare directly&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;typeof&lt;/span&gt; &lt;span class="nx"&gt;o1&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;object&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;o1&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="nx"&gt;o2&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="c1"&gt;// 5. Arrays - if one is array and other is not, they are not equal&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;Array&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;isArray&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;o1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nb"&gt;Array&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;isArray&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;o2&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nb"&gt;Array&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;isArray&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;o1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nb"&gt;Array&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;isArray&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;o2&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="c1"&gt;// If arrays have different lengths, they are not equal&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;o1&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="nx"&gt;o2&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="c1"&gt;// Compare each element of the arrays&lt;/span&gt;
    &lt;span class="k"&gt;for &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="nx"&gt;o1&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nf"&gt;areDeeplyEqual&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;o1&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="nx"&gt;o2&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]))&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="c1"&gt;// 6. Objects - if objects have different number of keys, they are not equal&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;Object&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;keys&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;o1&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="nb"&gt;Object&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;keys&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;o2&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="c1"&gt;// Compare each key-value pair of the objects&lt;/span&gt;
  &lt;span class="k"&gt;for &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt; &lt;span class="nb"&gt;Object&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;entries&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;o1&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;o2&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;hasOwnProperty&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nf"&gt;areDeeplyEqual&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;o2&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;]))&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This function is not perfect, it has some limitations.&lt;br&gt;
But it works for most cases. It was a good exercise to implement this function because it helped me understand how deep equality works in Javascript.&lt;/p&gt;


&lt;h3&gt;
  
  
  Performance comparison
&lt;/h3&gt;

&lt;p&gt;I was curious to see how these methods compare in terms of performance. So I wrote a simple function for generating random objects with huge number of keys and values.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="cm"&gt;/**
 * @param {number} size
 * @return {Object}
 */&lt;/span&gt;
&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;generateHugeObject&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;size&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;obj&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{};&lt;/span&gt;
  &lt;span class="k"&gt;for &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="nx"&gt;size&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// toString(36) converts the number to base 36 (0-9a-z)&lt;/span&gt;
    &lt;span class="c1"&gt;// substring(2, 12) removes the first two characters (0.)&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;key&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;random&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;toString&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;36&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;substring&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;12&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nx"&gt;obj&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;random&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;toString&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;36&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;substring&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;12&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;obj&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then I wrote a simple function to compare two objects using each of the methods. I used the &lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/Performance/now" rel="noopener noreferrer"&gt;performance.now()&lt;/a&gt; method to measure the time taken by each method.&lt;br&gt;
The results of this method are not very accurate and may vary from machine to machine, but it is good enough for our purpose.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;startFastDeepEqual&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;performance&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;now&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="nf"&gt;equal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;obj1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;obj2&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// true&lt;/span&gt;
&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;timeTakenFastDeepEqual&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;performance&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;now&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nx"&gt;startFastDeepEqual&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;startLodash&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;performance&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;now&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="nf"&gt;isEqual&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;obj1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;obj2&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// true&lt;/span&gt;
&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;timeTakenLodash&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;performance&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;now&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nx"&gt;startLodash&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;startNodeAssert&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;performance&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;now&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="nx"&gt;assert&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;deepStrictEqual&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;obj1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;obj2&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// true&lt;/span&gt;
&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;timeTakenNodeAssert&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;performance&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;now&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nx"&gt;startNodeAssert&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;startJSONStringify&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;performance&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;now&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;obj1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;obj2&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// true&lt;/span&gt;
&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;timeTakenJSONStringify&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;performance&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;now&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nx"&gt;startJSONStringify&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;startCustom&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;performance&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;now&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="nf"&gt;areDeeplyEqual&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;obj1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;obj2&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// true&lt;/span&gt;
&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;timeTakenCustom&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;performance&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;now&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nx"&gt;startCustom&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`FastDeepEqual: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;timeTakenFastDeepEqual&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`Lodash: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;timeTakenLodash&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`Node Assert: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;timeTakenNodeAssert&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`JSON.stringify: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;timeTakenJSONStringify&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`Custom: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;timeTakenCustom&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I ran this code with different sizes of objects and got the following results:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Size of object&lt;/th&gt;
&lt;th&gt;FastDeepEqual&lt;/th&gt;
&lt;th&gt;Lodash&lt;/th&gt;
&lt;th&gt;Node Assert&lt;/th&gt;
&lt;th&gt;JSON.stringify&lt;/th&gt;
&lt;th&gt;Custom&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;100&lt;/td&gt;
&lt;td&gt;0.0731&lt;/td&gt;
&lt;td&gt;0.4316&lt;/td&gt;
&lt;td&gt;0.0167&lt;/td&gt;
&lt;td&gt;0.0202&lt;/td&gt;
&lt;td&gt;0.2763&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;1000&lt;/td&gt;
&lt;td&gt;0.2522&lt;/td&gt;
&lt;td&gt;0.5901&lt;/td&gt;
&lt;td&gt;0.3884&lt;/td&gt;
&lt;td&gt;0.1584&lt;/td&gt;
&lt;td&gt;0.5741&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;10000&lt;/td&gt;
&lt;td&gt;2.3789&lt;/td&gt;
&lt;td&gt;3.0968&lt;/td&gt;
&lt;td&gt;3.0775&lt;/td&gt;
&lt;td&gt;2.7993&lt;/td&gt;
&lt;td&gt;7.3304&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;100000&lt;/td&gt;
&lt;td&gt;30.8043&lt;/td&gt;
&lt;td&gt;52.8975&lt;/td&gt;
&lt;td&gt;37.6808&lt;/td&gt;
&lt;td&gt;33.9532&lt;/td&gt;
&lt;td&gt;56.0962&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;500000&lt;/td&gt;
&lt;td&gt;173.8129&lt;/td&gt;
&lt;td&gt;200.1934&lt;/td&gt;
&lt;td&gt;219.5169&lt;/td&gt;
&lt;td&gt;311.2552&lt;/td&gt;
&lt;td&gt;448.4530&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;1000000&lt;/td&gt;
&lt;td&gt;398.3462&lt;/td&gt;
&lt;td&gt;455.5247&lt;/td&gt;
&lt;td&gt;531.1270&lt;/td&gt;
&lt;td&gt;736.3083&lt;/td&gt;
&lt;td&gt;1085.5547&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Graphical representation of the results:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fr6t6xk3p7u8cyvix107h.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fr6t6xk3p7u8cyvix107h.png" alt="Graphical representation of performance comparison of different methods of object comparison" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Obviously, my implementation is not optimized. Does anyone know how to improve it? Please let me know if you have any suggestions.&lt;br&gt;
Anyway, it was an interesting experiment, I learned how to use the performance.now() method and how to compare objects and arrays in Javascript.&lt;/p&gt;

&lt;p&gt;I hope this article was helpful to you. Thanks for reading!&lt;/p&gt;




&lt;p&gt;I'm always open to making new connections! Feel free to connect with me on &lt;a href="https://www.linkedin.com/in/aleksandr-efimenko" rel="noopener noreferrer"&gt;LinkedIn&lt;/a&gt;&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>programming</category>
      <category>tutorial</category>
      <category>learning</category>
    </item>
    <item>
      <title>Let’s implement a Debounce function in Javascript</title>
      <dc:creator>Alex</dc:creator>
      <pubDate>Mon, 01 Jan 2024 22:21:57 +0000</pubDate>
      <link>https://dev.to/alexefimenko/lets-implement-a-debounce-function-in-javascript-1ij1</link>
      <guid>https://dev.to/alexefimenko/lets-implement-a-debounce-function-in-javascript-1ij1</guid>
      <description>&lt;p&gt;A debounce function is used to limit the rate at which a function can fire.&lt;/p&gt;

&lt;p&gt;Previously I used &lt;a href="https://lodash.com/docs/4.17.15#debounce" rel="noopener noreferrer"&gt;Lodash’s debounce function&lt;/a&gt;, so I didn’t know how it worked and decided to implement it myself. I think it would be a good exercise and maybe help someone else come up with a better understanding of how it works.&lt;/p&gt;

&lt;p&gt;Check how debounce works:&lt;br&gt;
&lt;iframe src="https://codesandbox.io/embed/vnnplw"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;h3&gt;
  
  
  Real-life examples:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Doing an API call on every keypress in an input. If the user types fast, we will fire a lot of API calls, which is not good. We can use debounce to limit the rate at which the API calls are made.&lt;/li&gt;
&lt;li&gt;A button click is handled by a function that will only run once in a given period, such as the Save button. If the user clicks the button multiple times, we will only run the function once.&lt;/li&gt;
&lt;li&gt;When a user resizes a window or scrolls a page, which can trigger dozens or hundreds of calls in a small period of time.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Implementing a debounce function is not that hard. Two key concepts are used: closures and setTimeout.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;debounce&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;callback&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;interval&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;timeout&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;function &lt;/span&gt;&lt;span class="p"&gt;(...&lt;/span&gt;&lt;span class="nx"&gt;args&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;unknown&lt;/span&gt;&lt;span class="p"&gt;[])&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;timeout&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="nf"&gt;clearTimeout&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;timeout&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nx"&gt;timeout&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;setTimeout&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;callback&lt;/span&gt;&lt;span class="p"&gt;(...&lt;/span&gt;&lt;span class="nx"&gt;args&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="nx"&gt;interval&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Closure&lt;/strong&gt; is a function that has access to the parent scope, even after the parent function has closed. In our case, the parent function is the debounce function and the child function is the function that will be called after the wait time has passed. The child function will have access to the parent function’s scope, even after the parent function has closed.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;SetTimeout&lt;/strong&gt; is a function that will call a function after a given time has passed. SetTimeout returns a timer ID that can be used to cancel the timer by calling the clearTimeout function. We will use this to reset the timer if the function is called again before the wait time has passed.&lt;/p&gt;




&lt;p&gt;I'm always open to making new connections! Feel free to connect with me on &lt;a href="https://www.linkedin.com/in/aleksandr-efimenko" rel="noopener noreferrer"&gt;LinkedIn&lt;/a&gt;&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>leetcode</category>
      <category>tutorial</category>
      <category>programming</category>
    </item>
  </channel>
</rss>
