<?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: A. Rahman Bishal</title>
    <description>The latest articles on DEV Community by A. Rahman Bishal (@arbishal).</description>
    <link>https://dev.to/arbishal</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.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3237292%2F2d2859bf-abd9-4ce4-8400-2e198012beb9.jpg</url>
      <title>DEV Community: A. Rahman Bishal</title>
      <link>https://dev.to/arbishal</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/arbishal"/>
    <language>en</language>
    <item>
      <title>Starting with Spec-Driven Development: Spec first, Prompt later.</title>
      <dc:creator>A. Rahman Bishal</dc:creator>
      <pubDate>Wed, 01 Jul 2026 12:31:57 +0000</pubDate>
      <link>https://dev.to/arbishal/starting-with-spec-driven-development-spec-first-prompt-later-4o2e</link>
      <guid>https://dev.to/arbishal/starting-with-spec-driven-development-spec-first-prompt-later-4o2e</guid>
      <description>&lt;p&gt;Bringing the ideas I've been thinking about for months into life has never been easier, thanks to AI agents. The basic intuition is—give it a prompt, it builds the whole feature, the result looks good. Done. It takes only minutes to build the same thing that would've taken hours otherwise.&lt;br&gt;
Yes, I know, everyone's doing that. Right?&lt;br&gt;
The reason I'm opening like this is to point out what happened afterwards.&lt;br&gt;
I tried to use the search bar, and it fired a request on every keystroke.&lt;br&gt;
Wait, what? I didn't do that. Of course I'd add a debounce here. But the agent didn't. Why? I didn't ask it to. I said—build me a search bar, and it built me one that works; but I didn't say exactly what I wanted.&lt;br&gt;
Also, I noticed that the search button changes color on hover, but I'd already told it not to do that. The agent forgot, it hallucinated. What's missing then?&lt;br&gt;
What was missing was I did not provide the agent with the exact decisions to work with the feature; or did not provide a proper reference point to fallback to, to remediate the hallucination. In other words, I did not provide it with a proper spec. Hence, it took the hidden decisions itself; even though it pulled the feature off. This is the core problem that Spec-Driven Development (SDD) solves.&lt;/p&gt;
&lt;h2&gt;
  
  
  The Hidden Product Decisions Your AI Agent Is Making For You
&lt;/h2&gt;

&lt;p&gt;Here's what happens when you describe something to an AI agent and it generates code: lots of decisions get made. Let's take the search bar implementation as an example. Does the filtering happen on the client or the server? Does the URL update so results are shareable? What does an empty query show? Everything, or nothing?&lt;br&gt;
I tend to miss nitty-gritty details while reviewing tons of AI generated code in a short amount of time. The code works, the UI looks right, I move on… Every one of those is a decision that belongs to my product. If I don't make the decisions consciously, the agent takes them based on whatever pattern shows up most often in its training data.&lt;br&gt;
Take that search filter. Left to its devices the AI gives you something like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&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;e&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;fetchResults&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;target&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;filtered&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;results&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;item&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;
  &lt;span class="nx"&gt;item&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="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="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;activeCategory&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;category&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;query&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;&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Looks fine. But &lt;em&gt;AND&lt;/em&gt; logic might be wrong for my product. Maybe users expect &lt;em&gt;OR&lt;/em&gt;. Return &lt;em&gt;nothing&lt;/em&gt; on a query might be backwards from what my users need. That onChange is silently hitting my backend on every keystroke, firing off requests and abandoning them mid-flight.&lt;br&gt;
The agent did nothing except following the conventions it had in its training data. Convention just wasn't the answer for my specific situation and I never got the chance to weigh in.&lt;br&gt;
I used to think the fix was reviewing AI output carefully. But it doesn't always work. The problem was that by the time I was reviewing anything the decisions were already buried in code.&lt;/p&gt;

&lt;h2&gt;
  
  
  What a spec is, and what it isn't
&lt;/h2&gt;

&lt;p&gt;&lt;em&gt;"Write a spec first"&lt;/em&gt; can be inferred as a post-it-note to a 30-page PRD. Let me be more concrete.&lt;br&gt;
It's a markdown file. One file, written before I open my editor, that answers every behavioral question I can think of. What does the component render in each state? What interactions trigger what behavior? What happens at the edges? Not aspirational, not "we'll figure this out later." Decided.&lt;br&gt;
If you've done &lt;em&gt;Behavior-Driven Development (BDD)&lt;/em&gt;, a practice that defines feature behavior in plain language before writing any implementation, this is the same instinct with the tooling stripped away. BDD got the philosophy right, but the problem was it required maintaining a whole parallel infrastructure that most teams abandoned quietly after six months. A markdown file that an AI can read gets you the same thing without any of that overhead.&lt;br&gt;
It's not a new idea either. GitHub shipped a tool called spec-kit built specifically for this workflow in 2025. There's a heavier version too—machine-readable specs in OpenAPI or JSON Schema, where the spec itself generates tests and mocks automatically, but that's a real tooling investment. A markdown table gets you most of the benefit in twenty minutes, which is where I'd start.&lt;br&gt;
But the tooling isn't the interesting part. The interesting part is what happens when you sit down and try to write the spec.&lt;br&gt;
You'll get maybe two rows into your behavior table and hit a question you've never consciously asked yourself. What does "no results" look like? A message, an illustration, or nothing? If the user types while a request is in flight, do I cancel the old one or wait? Can users share a filtered URL with a teammate, or do filters live only in component state? Who owns this file when requirements change?&lt;br&gt;
That said, I must warn that a spec is only valuable if it stays current. If it drifts from what the code actually does, it becomes something worse than no spec—it's documentation that confidently lies.&lt;/p&gt;

&lt;h2&gt;
  
  
  How SDD Differs From Test-Driven Development (TDD)
&lt;/h2&gt;

&lt;p&gt;If you write tests first, this fits naturally. Test-Driven Development (TDD)—the practice of writing failing tests before writing the code that makes them pass, makes you consistent. It doesn't make you right. You can write a test that encodes the wrong behavior, and that test will defend that wrong behavior forever. Tests verify implementation, but what verifies the tests?&lt;br&gt;
The spec. That's the decision source above the tests. If a test fails, fix the code. If the spec changes, you update the spec first, then the test, then the code. In that order, always. For me it doesn't feel like adding a layer on top of TDD—it is a source of truth that validates my tests.&lt;/p&gt;

&lt;h2&gt;
  
  
  The SDD Workflow in Practice: Spec, Tests, Implementation
&lt;/h2&gt;

&lt;p&gt;Let's proceed with the same component—a search and filter UI for a product listing. The kind of thing I could prompt for without thinking.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 1: Defining the spec.
&lt;/h3&gt;

&lt;p&gt;I opened a blank &lt;strong&gt;SPEC.md&lt;/strong&gt; and started filling in scenarios. Just this forced me to make decisions I'd have otherwise skipped entirely.&lt;br&gt;
The debounce question came up immediately—once I wrote "user types query" as a row, I had to fill in the behavior column. And that pulled in the next question: what if they type faster than the debounce window? What if a request is already in flight when the debounce fires?&lt;br&gt;
The URL update requirement showed up because I asked myself: can a user share a filtered search with a friend? A product question, not a technical one. It wouldn't have occurred to me in a prompt.&lt;br&gt;
Here's what the spec looked like when I was done:&lt;br&gt;
SearchFilter component&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;State / Interaction&lt;/th&gt;
&lt;th&gt;Behavior&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Page loads, no query or filters&lt;/td&gt;
&lt;td&gt;Show all results&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;User types query&lt;/td&gt;
&lt;td&gt;Debounce 300ms, then fetch&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;User types while in-flight req&lt;/td&gt;
&lt;td&gt;Cancel previous, start new debounce&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Results returned&lt;/td&gt;
&lt;td&gt;Replace list, update URL params&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Query returns no results&lt;/td&gt;
&lt;td&gt;Show "No results for [query]"&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;User clears query&lt;/td&gt;
&lt;td&gt;Reset to all results immediately&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;User applies category filter&lt;/td&gt;
&lt;td&gt;AND logic with active query, fetch now&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Multiple filters active&lt;/td&gt;
&lt;td&gt;AND logic—must match all&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Request takes &amp;gt; 200ms&lt;/td&gt;
&lt;td&gt;Show loading skeleton&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Request fails&lt;/td&gt;
&lt;td&gt;Inline error, preserve previous results&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;ul&gt;
&lt;li&gt;Case-insensitive matching&lt;/li&gt;
&lt;li&gt;URL updates on every search (q= and category= params)—results are shareable&lt;/li&gt;
&lt;li&gt;Sort order persists across filter changes&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It's more rows than you'd expect for a "simple" component. That's kind of the point.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 2: Writing the tests.
&lt;/h3&gt;

&lt;p&gt;Then I handed the spec to the agent: &lt;em&gt;Read SPEC.md and write contract tests derived from it. Do not write any implementation yet.&lt;/em&gt;&lt;br&gt;
The first pass came back testing things I hadn't specified. I pushed back. The second pass was better but still had invented behavior. The third pass was finally just the spec, nothing else.&lt;br&gt;
This is worth mentioning: "read the spec and write tests" is not a magic prompt. The agent will add its own ideas. Treat the generated tests like a pull request—read every line.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;The thing that breaks this workflow most often: Don't ask the agent to write both the spec and the tests from scratch. If you do, they'll agree with each other—and they might both be wrong. The AI bakes its assumptions into the spec, writes tests that enforce those assumptions, and you end up with a green test suite that proves nothing. This is why the spec has to come from you. The AI can help you think through edge cases, but the decisions have to be yours before the tests are written.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Step 3: Implementation.
&lt;/h3&gt;

&lt;p&gt;Once the tests were genuinely spec-derived and failing, I prompted for implementation: read the spec, make the tests pass, add nothing that isn't in the spec. Green. Done. No guessing about debounce timing, no creative interpretation of empty state. The AI moved fast because it had something specific to work against.&lt;br&gt;
One rule I kept the whole time: if a test fails after implementation, I fix the code. Never the test. The moment you change a test to make code pass, you've quietly changed the spec—and the whole point was that the spec is yours, not the AI's.&lt;/p&gt;

&lt;h2&gt;
  
  
  What SDD doesn't solve
&lt;/h2&gt;

&lt;p&gt;SDD doesn't help if the spec is wrong. If I specify the wrong behavior, wrong status codes, wrong business logic, wrong security model—the implementation will faithfully build exactly that. A good spec process catches a lot of mistakes, but it's not magic. I still have to think carefully, and thinking carefully is a skill that takes practice.&lt;br&gt;
Writing a good spec is also harder than it looks the first few times. The tendency is to write the happy path and stop. The edge cases, the error scenarios, the security implications—those take effort to surface.&lt;br&gt;
And finally, SDD doesn't replace domain knowledge. If you don't understand the problem well enough, the spec will reflect that. Talking to users, understanding the system's context, knowing what actually matters—none of that gets skipped just because you wrote a spec first.&lt;br&gt;
What SDD does is make your thinking visible before it becomes code. If the thinking is wrong, you find out faster and cheaper. If it's right, the rest of the process gets dramatically smoother.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why AI Agents Make Spec-Driven Development More Critical Than Ever
&lt;/h2&gt;

&lt;p&gt;SDD has always been good practice. Skipping the thinking used to be recoverable. You'd catch the missing case in code review, or QA, or production where you'd patch fast and learn something.&lt;br&gt;
AI collapsed that timeline. The gap between "vague idea" and "running code" used to be hours of manual work, and somewhere in those hours you'd catch the questions you hadn't answered. Now it's seconds. The questions don't surface. They get buried under code that already passes tests.&lt;br&gt;
SDD puts the thinking back at the front—before the prompts, before the code, before anything runs. Not because AI is bad at generating code. Because deciding what to build is still your job, and always will be.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Spec first. Prompt later.&lt;/p&gt;
&lt;/blockquote&gt;

</description>
      <category>ai</category>
      <category>productivity</category>
      <category>learning</category>
    </item>
    <item>
      <title>Of Type and Interface: TypeScript Tales Ch. 01</title>
      <dc:creator>A. Rahman Bishal</dc:creator>
      <pubDate>Wed, 19 Nov 2025 09:24:21 +0000</pubDate>
      <link>https://dev.to/arbishal/of-type-and-interface-typescript-tales-ch-01-39de</link>
      <guid>https://dev.to/arbishal/of-type-and-interface-typescript-tales-ch-01-39de</guid>
      <description>&lt;p&gt;As you are reading this, I’m going to assume that you have a basic idea of what TypeScript is (&lt;em&gt;which is basically JavaScript with syntax for types,&lt;/em&gt; according to the official docs). The purpose of this piece of writing is to discuss and look into the contrast between two commonly used constructs widely used in TypeScript: &lt;strong&gt;&lt;em&gt;Type&lt;/em&gt;&lt;/strong&gt;, and &lt;strong&gt;&lt;em&gt;Interface&lt;/em&gt;&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;In short, we use &lt;strong&gt;&lt;em&gt;type&lt;/em&gt;&lt;/strong&gt; as &lt;em&gt;type aliases&lt;/em&gt;, which is, a name for any type. With the help of this, we can use the same type more than once and refer to it by a single name. On the other hand, &lt;strong&gt;&lt;em&gt;interface&lt;/em&gt;&lt;/strong&gt;, or &lt;em&gt;interface declaration&lt;/em&gt; is basically another way to name an object type, actually a contract for a structure.&lt;/p&gt;

&lt;p&gt;Now, they may not seem very similar by the definition. But here we are here, talking about what are the differences, and maybe trying to choose only one between &lt;em&gt;type&lt;/em&gt; and &lt;em&gt;interface&lt;/em&gt;, there should be some similarities that might make you confused, right?&lt;/p&gt;

&lt;p&gt;In a bunch of cases, we can use type and interface interchangeably, and choose them freely. For object shapes and function signatures, both can work the same way. Let’s see an example. We will define objects and functions using both type and interface.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="c1"&gt;// defining object&lt;/span&gt;

&lt;span class="nx"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;ObjectType&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="nx"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;author&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;number&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nf"&gt;fun&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="k"&gt;void&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;thrillerBook&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;ObjectType&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;ObjectInterface&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="nx"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;author&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;number&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nf"&gt;fun&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="k"&gt;void&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;fantasyBook&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;ObjectInterface&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// defining function&lt;/span&gt;

&lt;span class="nx"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;FunctionType&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;author&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&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="nx"&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;getAcademicAuthor&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;FunctionType&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;author&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="s2"&gt;`The academic author is &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;author&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="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;FunctionInterface&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;author&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;string&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nx"&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;getFictionAuthor&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;FunctionInterface&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;author&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="s2"&gt;`The fiction author is &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;author&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;But yes, there are some obvious differences. Both of the keywords has some superpowers of their own, that the other one does not have. Let’s dive into those.&lt;/p&gt;

&lt;h2&gt;
  
  
  Superpowers of &lt;strong&gt;&lt;em&gt;type&lt;/em&gt;&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;You can use &lt;strong&gt;&lt;em&gt;type&lt;/em&gt;&lt;/strong&gt; to represent anything from primitives, unions, tuples, and various complex type. But &lt;strong&gt;&lt;em&gt;interface&lt;/em&gt;&lt;/strong&gt; is mostly limited to defining &lt;em&gt;shapes&lt;/em&gt; e. g. objects (as well as callable &amp;amp; constructable signatures).&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="nx"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;Title&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;                &lt;span class="c1"&gt;// primitive&lt;/span&gt;
&lt;span class="nx"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;Published&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;string&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nx"&gt;number&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;   &lt;span class="c1"&gt;// union&lt;/span&gt;
&lt;span class="nx"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;Binding&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;string&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;    &lt;span class="c1"&gt;// tuples&lt;/span&gt;
&lt;span class="nx"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;Spine&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;flat&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="s2"&gt;round&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;      &lt;span class="c1"&gt;// template literal&lt;/span&gt;
&lt;span class="nx"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;ReadonlyBook&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;readonly&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="nx"&gt;keyof&lt;/span&gt; &lt;span class="nx"&gt;Book&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt; &lt;span class="nx"&gt;Book&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="c1"&gt;// mapped types&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;There are cases, when we must fall back to using type alias. We can roughly list them down like this:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Union types&lt;/li&gt;
&lt;li&gt;Intersection types&lt;/li&gt;
&lt;li&gt;Mapped types&lt;/li&gt;
&lt;li&gt;Conditional types&lt;/li&gt;
&lt;li&gt;Template literal types&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These are some mere examples that &lt;strong&gt;&lt;em&gt;interface&lt;/em&gt;&lt;/strong&gt; does not support. It can be used for far more complex typing.&lt;/p&gt;

&lt;h2&gt;
  
  
  Superpowers of &lt;em&gt;interface&lt;/em&gt;
&lt;/h2&gt;

&lt;p&gt;While using &lt;strong&gt;&lt;em&gt;interface&lt;/em&gt;&lt;/strong&gt; for defining shapes or structure, there are several perks over using &lt;strong&gt;&lt;em&gt;type&lt;/em&gt;&lt;/strong&gt;. One of the major distinctions between &lt;strong&gt;&lt;em&gt;type&lt;/em&gt;&lt;/strong&gt; and &lt;strong&gt;&lt;em&gt;interface&lt;/em&gt;&lt;/strong&gt; is that type cannot be re-opened and redeclared, whereas interface can be. We call this &lt;code&gt;declaration merging&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;Book&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;title&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;author&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;string&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;Book&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;published&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;number&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nx"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nf"&gt;reprint&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// we can do this, no error.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, if we declare an object of type Book, it will have all the properties from both definitions, i. e. title, author, published, reprint(). But such is not the case for type.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="nx"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;Movie&lt;/span&gt; &lt;span class="o"&gt;=&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="nx"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;released&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;number&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nx"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;Movie&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;director&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&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;// we cannot do this, TS will throw error.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To achieve the same with &lt;strong&gt;&lt;em&gt;type&lt;/em&gt;&lt;/strong&gt;, we must define a new type, and &lt;strong&gt;&lt;em&gt;intersect&lt;/em&gt;&lt;/strong&gt; the old one with it. Something like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="nx"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;MovieWithDirector&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;Movie&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;director&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&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;But this method has a little overhead comparing to the one we saw earlier with &lt;em&gt;declaration merging&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;Even though &lt;em&gt;declaration merging&lt;/em&gt; is one of the biggest superpowers of interface, it comes with a warning label—&lt;strong&gt;&lt;em&gt;overusing merging can make the codebase harder to reason about&lt;/em&gt;&lt;/strong&gt;. &lt;/p&gt;

&lt;h2&gt;
  
  
  Extensions and Implementations
&lt;/h2&gt;

&lt;p&gt;An interface can &lt;code&gt;extend&lt;/code&gt; both interface, and a type. Remember the Book interface and the Movie type we defined earlier in the example? Let’s extend those:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="c1"&gt;// interface extends another interface&lt;/span&gt;
&lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;PaperbackBook&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nx"&gt;Book&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;binding&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;paperback&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;// interface extends another type alias&lt;/span&gt;
&lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;AnimatedMovie&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nx"&gt;Movie&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;medium&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&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;But remember, for an interface to be able to extend a type alias, it must be of an object type. For example, the below extension is not possible.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="nx"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;Magic&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;number&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nx"&gt;string&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;string&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nx"&gt;number&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;Technology&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nx"&gt;Magic&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;// this will throw an error&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The bottom line is, interfaces can extend other interfaces and sometimes type aliases if they define shapes. But the opposite is not possible in the same way. For that, we have to use &lt;em&gt;intersection&lt;/em&gt;, as we did before to mock &lt;em&gt;declaration merging&lt;/em&gt; with type aliases.&lt;/p&gt;

&lt;p&gt;This scenario remains the same if a class tries to &lt;code&gt;implement&lt;/code&gt; either of these. Let’s continue with the previously declared &lt;em&gt;Book&lt;/em&gt; &lt;strong&gt;&lt;em&gt;interface&lt;/em&gt;&lt;/strong&gt; and &lt;em&gt;Movie&lt;/em&gt; &lt;strong&gt;&lt;em&gt;type&lt;/em&gt;&lt;/strong&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="c1"&gt;// a class implements an interface&lt;/span&gt;
&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;FantasyBook&lt;/span&gt; &lt;span class="kr"&gt;implements&lt;/span&gt; &lt;span class="nx"&gt;Book&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;title&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;The Hobbit&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nx"&gt;author&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;John Ronald Reuel Tolkien&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nx"&gt;published&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1937&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nf"&gt;reprint&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;reprint this again!&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="c1"&gt;// a class implements a type alias&lt;/span&gt;
&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;AnimatedMovie&lt;/span&gt; &lt;span class="kr"&gt;implements&lt;/span&gt; &lt;span class="nx"&gt;Movie&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;title&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Tarzan&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nx"&gt;released&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1999&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nx"&gt;isFavouriteMovie&lt;/span&gt; &lt;span class="o"&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;But, same as before, the type alias must define a shape i.e. an object. Otherwise, it cannot be implemented.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="nx"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;NoShape&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;number&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nx"&gt;string&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;string&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nx"&gt;number&lt;/span&gt;&lt;span class="p"&gt;[];&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Shape&lt;/span&gt; &lt;span class="kr"&gt;implements&lt;/span&gt; &lt;span class="nx"&gt;NoShape&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;// this will throw an error&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;So, for its very nature, interface can be extended or implemented however we like, without any worries, as they define a shape. But as type alias is more of a broader toolbox for type definition, there are some limitations and cases where we need to be careful.&lt;/p&gt;

&lt;p&gt;Now, the end is nigh, and I shall conclude this with a million dollar question:&lt;/p&gt;

&lt;h2&gt;
  
  
  Type or Interface, which one to use?
&lt;/h2&gt;

&lt;p&gt;As both &lt;strong&gt;&lt;em&gt;type&lt;/em&gt;&lt;/strong&gt; and &lt;strong&gt;&lt;em&gt;interface&lt;/em&gt;&lt;/strong&gt; share some common use cases, the question is: &lt;em&gt;which one to use&lt;/em&gt;?&lt;/p&gt;

&lt;p&gt;Well, actually, there is no obvious choice. At the end, it really depends on you. But before deciding that, here are some facts:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;TypeScript provides better and &lt;em&gt;more focused error messages&lt;/em&gt; while working with &lt;strong&gt;&lt;em&gt;interface&lt;/em&gt;&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;em&gt;Interface&lt;/em&gt;&lt;/strong&gt; was supposed to be slightly more performant than &lt;strong&gt;&lt;em&gt;type&lt;/em&gt;&lt;/strong&gt;. But this difference is practically negligible in most cases (i. e. if the defined type is not very complex or deeply nested), specially in the later versions. After version 4.0, there is &lt;strong&gt;&lt;em&gt;no measurable performance difference&lt;/em&gt;&lt;/strong&gt; in real-world scenarios—stated publicly by the &lt;em&gt;TypeScript Team&lt;/em&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;em&gt;Interface&lt;/em&gt;&lt;/strong&gt; has closer mapping with objects by definition.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In case of common use cases, like defining an object, or writing a contract for a class, using interface seems more intuitive from object oriented perspective. But we have no way to avoid &lt;strong&gt;&lt;em&gt;type&lt;/em&gt;&lt;/strong&gt; in some cases also i. e. while working with union types or so.&lt;/p&gt;

&lt;p&gt;The official TypeScript docs suggests to "&lt;strong&gt;&lt;em&gt;Use&amp;nbsp;&lt;code&gt;interfaces&lt;/code&gt;&amp;nbsp;until you need to use features from&amp;nbsp;&lt;code&gt;type&lt;/code&gt; aliases&lt;/em&gt;&lt;/strong&gt;". This pretty much infers to “&lt;em&gt;Use &lt;code&gt;interfaces&lt;/code&gt; to define the shape of objects. Use &lt;code&gt;type&lt;/code&gt; aliases for more advanced type composition.&lt;/em&gt;”  For your convenience, I can provide a decision tree—&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Use &lt;code&gt;interface&lt;/code&gt; when:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;You want declaration merging.&lt;/li&gt;
&lt;li&gt;You want cleaner IntelliSense names.&lt;/li&gt;
&lt;li&gt;You want the error messages to make more sense.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Use &lt;code&gt;type&lt;/code&gt; when:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;You need unions, intersections, mapped types, template literals.&lt;/li&gt;
&lt;li&gt;You work with utility types (&lt;code&gt;Partial&lt;/code&gt;, &lt;code&gt;Pick&lt;/code&gt;, etc.).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;But if you are still confused, just go with whichever you are comfortable with. But, it is recommended to be consistent on the choice. Choose the approach that better suits your style and keeps the code more readable and maintainable.&lt;/p&gt;

&lt;p&gt;Keep in mind that, these are compile-time only constructs. After being compiled into JavaScript, no trace of type or interface remains. So choosing one or another does not affect runtime perfomance.&lt;/p&gt;

&lt;h3&gt;
  
  
  References
&lt;/h3&gt;

&lt;p&gt;TypeScript Handbook: &lt;a href="https://www.typescriptlang.org/docs/handbook/2/everyday-types.html" rel="noopener noreferrer"&gt;https://www.typescriptlang.org/docs/handbook/2/everyday-types.html&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Playground Examples 1:  &lt;a href="https://tinyurl.com/4cwazrus" rel="noopener noreferrer"&gt;https://tinyurl.com/4cwazrus&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Playground Examples 2: &lt;a href="https://tinyurl.com/4hu8ebsy" rel="noopener noreferrer"&gt;https://tinyurl.com/4hu8ebsy&lt;/a&gt;&lt;/p&gt;

</description>
      <category>beginners</category>
      <category>javascript</category>
      <category>typescript</category>
    </item>
    <item>
      <title>The Magical CSS Display Property: Contents!</title>
      <dc:creator>A. Rahman Bishal</dc:creator>
      <pubDate>Tue, 18 Nov 2025 12:13:08 +0000</pubDate>
      <link>https://dev.to/arbishal/the-magical-css-display-property-contents-5bmh</link>
      <guid>https://dev.to/arbishal/the-magical-css-display-property-contents-5bmh</guid>
      <description>&lt;p&gt;There are a bunch of display properties in CSS. If you don’t write CSS frequently, you might have missed a cool property that was introduced relatively recently, though it’s not that old either (started gaining support across major browsers around 2018). Well, I’m talking about &lt;code&gt;display: contents&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  What does contents do?
&lt;/h2&gt;

&lt;p&gt;The HTML elements like div, span, etc. are wrapped by an invisible box around themselves where we can specify their paddings, margins, and whatnot. So, in general, we work with boxes. But when display: contents is applied, that box seems to magically vanish. Rather, it will be replaced by its pseudo-elements or child-elements. Or you can say, pseudo-boxes or child-boxes. It’s like that box doesn’t exist. Let’s see an example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;div id=”parent-contatiner”&amp;gt;
  &amp;lt;div id="container" style="display: contents"&amp;gt;
    &amp;lt;h3&amp;gt; I am a Panda! &amp;lt;/h3&amp;gt;
    &amp;lt;p&amp;gt; I love a Cat! &amp;lt;/p&amp;gt;
  &amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The container div will not have a box around it, and it will not be visible. Rather, it will be replaced by its children i. e. the &lt;em&gt;h3&lt;/em&gt; and &lt;em&gt;p&lt;/em&gt; elements. So now, they are no longer the &lt;em&gt;container&lt;/em&gt;’s children, but the &lt;em&gt;parent-container&lt;/em&gt;’s children. It will not be gone from the DOM-Tree, it’s just that the Tree will pretend as if it’s not there. Cool right?&lt;/p&gt;

&lt;h2&gt;
  
  
  Where do I use contents?
&lt;/h2&gt;

&lt;p&gt;You may ask, if the container itself disappears, all the styles and events will be gone, too? The answer is, no. You will still have the events attached to it, and the only styles you will lose are the styles related to box generation (like margin, padding, border, etc). So, where do we use it?&lt;/p&gt;

&lt;p&gt;Well, I can give you two scenarios right away.&lt;/p&gt;

&lt;p&gt;First, when you need to wrap something within a content for semantic readability, but doing so will break your design. By using contents, you will be able to stand in a sweet spot where you have both — semantic readability and the required design.&lt;/p&gt;

&lt;p&gt;Second, you might face a situation, where all your elements need to be direct children of a container that is using flex or grid. You need to apply some styling on some children based on a condition or so. In that case, you can wrap those children within a container with &lt;code&gt;display: contents&lt;/code&gt; based on that condition.&lt;/p&gt;

&lt;p&gt;Does this sound like a little gibberish to you? Ok, then let me tell you how I found this property in the first place.&lt;/p&gt;

&lt;h2&gt;
  
  
  A little practice for you!
&lt;/h2&gt;

&lt;p&gt;Let me explain the problem first. I was working on a responsive web page using a mobile-first approach. I had three boxes. In the desktop view they will be shown side by side, just like Image 1 —&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%2F57u1ewhaypoecf6z0wyy.webp" 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%2F57u1ewhaypoecf6z0wyy.webp" alt=" " width="680" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Plain and simple flex-row, right? But in the mobile view, Box2 and Box3 will be shown like a stack and this stack will be side by side with Box1 like Image 2 —&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%2Fz4uq6h2om0qqovdge7ed.webp" 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%2Fz4uq6h2om0qqovdge7ed.webp" alt=" " width="680" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now, how can you achieve that? Think about it. This will introduce you to &lt;em&gt;contents&lt;/em&gt; and you might as well have a little hands-on experience!&lt;/p&gt;

&lt;p&gt;Let me give you my solution. (Please note that this might not be the only way. It’s just how I solved it personally, and I think it’s neat!)&lt;/p&gt;

&lt;p&gt;I have the three boxes inside a parent-container having display: flex applied. I just wrapped Box2 and Box3 in a container. When we are in the mobile view, this container will have display: flex. So now, Box1 and the container are siblings and flex property will only apply to these two. Box2 and Box3 will have separate flex properties applied to them via the container. But when we are in the desktop view, this container will have display: contents. So, in the desktop view, the container visually disappears, and Box2 and Box3 are direct children of the parent-container. Now all three boxes are siblings and flex property from the parent-container applies to all of them. That’s it.&lt;/p&gt;

&lt;p&gt;The code may 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;&amp;lt;div class="outer-container"&amp;gt;
  &amp;lt;span&amp;gt; Box1 &amp;lt;/span&amp;gt;
  &amp;lt;div class="inner-container"&amp;gt;
    &amp;lt;span&amp;gt; Box2 &amp;lt;/span&amp;gt;
    &amp;lt;span&amp;gt; Box3 &amp;lt;/span&amp;gt; 
  &amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;.outer-container {
  display: flex;
  flex-direction: row;
}

.inner-container {
  display: flex;
  flex-direction: column;
}

@media only screen and (max-width: &amp;lt;breakpoint&amp;gt;px) {
  .inner-container {
    display: contents;
  }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A tiny note with warning!&lt;br&gt;
I should mention that this property does not work the same with all the elements. There are some elements that are not rendered purely by the CSS box concepts may behave differently. Please see &lt;a href="https://developer.mozilla.org/en-US/docs/Web/CSS/Reference/Properties/display#box" rel="noopener noreferrer"&gt;this doc&lt;/a&gt; for further reference.&lt;/p&gt;

&lt;p&gt;So, yeah, that’s how I’ve found &lt;code&gt;display: contents&lt;/code&gt;, and I think it works like magic. No?&lt;/p&gt;

</description>
      <category>css</category>
      <category>html</category>
      <category>frontend</category>
    </item>
  </channel>
</rss>
