cf.completefrontend
Open lab My progress
THE TYPESCRIPT FIELD GUIDE

Type aliases & interfaces

Give a type a name with type or interface, build one type on another with extends and &, and choose between them, with code you can edit and break.

By the end, you can
  • 01
    Name a typeWrite a type alias or an interface once and use its name everywhere, so one change is checked at every use.
  • 02
    Build on a typeMake one type from another with interface … extends or with &, and read the error when a property clashes.
  • 03
    Choose between themSay what only a type alias can do, what only an interface can do, and pick one for an object, a union, or a library type.

Write a type once, use its name everywhere

A shop page has two small functions. One builds a label for a product, like Tea: $3. The other adds up a cart. Both take products, so both write out what a product is:

The same object type, written twicePop out in the code editor (opens in a new tab)TypeScript
function productLabel(product: { name: string; price: number }) {  return `${product.name}: $${product.price}`;} function cartTotal(items: { name: string; price: number }[]) {  let total = 0;  for (const item of items) total += item.price;  return total;} console.log(productLabel({ name: "Tea", price: 3 }));console.log(cartTotal([{ name: "Tea", price: 3 }, { name: "Cake", price: 4 }]));

Line 1 says productLabel takes a product with a name that is a string and a price that is a number. Line 2 builds the label with a template literal. Line 5 writes the same shape again, with [] after it: cartTotal takes a list of those products. Lines 6 to 8 add up the prices. Line 11 prints Tea: $3 and line 12 prints 7. There are no errors.

The code works, but { name: string; price: number } appears twice. Each copy is long to read. And when products get a new property, you have to find every copy and change each one. Miss one, and two parts of the page disagree about what a product is.

TypeScript lets you give a type a name. You write the type once, and then use the name wherever the type goes. A name made with the type keyword is called a type alias. ("Alias" means "another name for the same thing".) Here is the same code with one:

The shape named Product (an error on purpose)Pop out in the code editor (opens in a new tab)TypeScript
type Product = { name: string; price: number }; function productLabel(product: Product) {  return `${product.name}: $${product.price}`;} function cartTotal(items: Product[]) {  let total = 0;  for (const item of items) total += item.price;  return total;} const tea: Product = { name: "Tea", price: 3 };//    ^?const cake: Product = { name: "Cake", price: "4" };console.log(productLabel(tea));console.log(cartTotal([tea, cake]));

Line 1 is new: type Product = … gives the name Product to the object type. Read it as "a Product is an object with a string name and a number price". Line 3 now says product: Product, and line 7 says items: Product[], a list of products. Line 13 makes the tea, and the query on line 14 shows its type by name: const tea: Product.

Line 15 gives the cake a price in quotes, and TypeScript marks it on purpose, because it's a bug: Type 'string' is not assignable to type 'number'. That means "you're putting text where a number has to go". The name changed nothing about the checking: TypeScript looked up what Product means and checked the cake against it. Run it anyway, and line 16 prints Tea: $3, but line 17 prints 34, because 3 + "4" joins the two as text.

A tag named Product points at one card: { name: string; price: number }, the type written once. Below, product: Product and items: Product[] both point up at the tag.the nameProductthe type, written once{ name: string; price: number }product: Productitems: Product[]
You write the shape once and give it the name Product. The parameters product: Product and items: Product[] both use the name, so both mean that one shape.

The name pays off when the type changes. The playground below has two products and the label function. Each button changes only line 1, the type. Watch which lines get errors:

Playground: change the type in one place
Two products and a labelPop out in the code editor (opens in a new tab)TypeScript
type Product = { name: string; price: number }; const tea: Product = { name: "Tea", price: 3 };const cake: Product = { name: "Cake", price: 4 }; function productLabel(product: Product) {  return `${product.name}: $${product.price}`;}console.log(productLabel(tea));
Console outputTea: $3
What happens
Lines that say Product3, 4, 6
TypeScriptNo errors
Try it yourself

Line 1 says a product has a name and a price. Lines 3 and 4 match it, and line 7 reads a price that exists. No errors, and the code prints Tea: $3.

TypeScript checks the code for real each time you press a button. Each button changes only line 1. Reset goes back to As it is.

Add inStock changes one line, and TypeScript marks lines 3 and 4: both products are now missing inStock. Add inStock? makes it optional, with a question mark, so the errors go. Remove price marks three lines: the two objects that still have a price, and line 7, which reads one. You changed the type in one place, and TypeScript gave you a list of every place to update. The output stays Tea: $3 each time, because types never change what the code does.

Real-life analogyA saved address in a delivery app

Typing your full address for every order is slow, and one typo sends a parcel to the wrong street. So a delivery app lets you save the address once, under a short name like Home. At checkout you just pick Home. When you move, you edit Home in one place, and every new order uses the new address.

In real life: The full address: 12 Lake Road, Pune
In TypeScript: The type: { name: string; price: number }
In real life: You save it once under the name Home
In TypeScript: You write type Product = … once
In real life: At checkout, you pick Home
In TypeScript: You write product: Product
In real life: You edit Home once, and every new order uses the new address
In TypeScript: You change the type once, and TypeScript checks every place that uses Product
The main idea

A type alias or an interface gives a type a name. You write the type once, like type Product = { name: string; price: number }, and use the name everywhere the type goes. TypeScript checks each use against what the name means. A type alias can name any type; an interface names an object shape.

Type aliases: a name for any type

A type alias is the word type, a name, an equals sign, and a type. Names of types start with a capital letter by habit, like Product, so you can tell them apart from variables. The type after the = can be any type at all, not only an object:

Three aliases for a user (an error on purpose)Pop out in the code editor (opens in a new tab)TypeScript
type Plan = "free" | "pro";type Email = string;type User = { name: string; email: Email; plan: Plan }; const asha: User = { name: "Asha", email: "asha@example.com", plan: "pro" };const ben: User = { name: "Ben", email: "ben@example.com", plan: "gold" };console.log(asha.plan);

Line 1 names a union: a Plan is the exact text "free" or the exact text "pro", and nothing else (a type that is one exact value is a literal type). Line 2 gives string a second name, Email, which tells a reader what the text is for. Line 3 names an object type, and its properties use the two aliases from lines 1 and 2. Line 5 makes Asha, on the pro plan, which fits.

Line 6 puts Ben on a "gold" plan, and TypeScript marks it on purpose: Type '"gold"' is not assignable to type 'Plan'. The message uses the name, so you can read it as ""gold" isn't one of the plans". Line 7 still prints pro when it runs.

Try it yourself. The box below fills in the type on line 1 of a ProductId alias. Line 3 gives the tea the id 7, and line 4 gives the cake the id "c-4". Type different types and watch the list under the code:

Playground: type what ProductId names
Two product idsPop out in the code editor (opens in a new tab)TypeScript
type ProductId = number; const teaId: ProductId = 7;const cakeId: ProductId = "c-4";console.log(teaId, cakeId);
ProductId meansnumber
What happens
TypeScript1 error: line 4
When it runsprints 7 c-4
Try it yourself

ProductId means number. Line 3's 7 fits, but line 4's "c-4" is text: Type 'string' is not assignable to type 'number'.

The code is checked by the real TypeScript compiler each time you type. Only line 1 changes. Reset puts number back.

With number, the cake's text id gets an error; with string, the tea's number id does. With number | string, both fit and the errors are gone. Whatever you type, the code prints 7 c-4 when it runs: the alias only tells TypeScript what to check.

An alias doesn't make a new type. It's another name for the same type, and TypeScript treats the two as one:

Email is just another name for stringPop out in the code editor (opens in a new tab)TypeScript
type Email = string; const email: Email = "asha@example.com";//    ^?const loud = email.toUpperCase();console.log(loud);

Line 1 makes Email another name for string. Line 3 says email is an Email. The query on line 4 shows const email: string: for an alias of a simple type like string, TypeScript shows the type itself. Line 5 calls a string method, and line 6 prints ASHA@EXAMPLE.COM. Any string fits an Email, even "hello", because the two names mean the same type. (The Structural typing lesson shows more of this.)

Interfaces: a name for an object shape

The second way to name a type is an interface. You write the word interface, a name, and the properties inside braces. There's no equals sign. An interface can only describe an object shape: which properties an object has, and the type of each.

A User interface (an error on purpose)Pop out in the code editor (opens in a new tab)TypeScript
interface User {  name: string;  email: string;  nickname?: string;} function greet(user: User) {  return `Hi, ${user.nickname ?? user.name}`;} const asha: User = { name: "Asha", email: "asha@example.com" };//    ^?console.log(greet(asha));console.log(greet({ name: "Ben" }));

Lines 1 to 5 are the interface. A User has a name and an email, both strings, and may have a nickname: the question mark on line 4 makes it optional, just as in an object type. Line 7 says greet takes a User. Line 8 uses the nickname if there is one, or the name otherwise, with ??. Line 11 makes Asha, and the query on line 12 shows const asha: User. Line 13 prints Hi, Asha.

Line 14 passes Ben with no email, and TypeScript marks it on purpose. The message has two lines:

  • Argument of type '{ name: string; }' is not assignable to parameter of type 'User' means "the object you passed doesn't fit what greet asks for".
  • Property 'email' is missing in type '{ name: string; }' but required in type 'User' says why: a User must have an email, and Ben's object has none.

Run it anyway and line 14 prints Hi, Ben: the function only reads names, so the missing email doesn't show yet. It would, the first time some other code sent Ben an email.

For an object, a type alias and an interface mean the same thing. TypeScript compares the shapes, so one can stand in for the other:

A type alias and an interface with the same shapePop out in the code editor (opens in a new tab)TypeScript
type Product = { name: string; price: number }; interface ShopItem {  name: string;  price: number;} const tea: Product = { name: "Tea", price: 3 };const sameTea: ShopItem = tea;console.log(sameTea.price);

Line 1 names the shape with a type alias, Product. Lines 3 to 6 name the same shape with an interface, ShopItem. Line 8 makes a Product, and line 9 stores it as a ShopItem with no error, because both names describe an object with a string name and a number price. Line 10 prints 3.

Building one type on another

Often one type is another type plus a little more. An admin on a shop's account page is a user with a list of things they are allowed to do. You don't want to copy the user's properties into the admin; you want to say "an admin is a user, plus this". An interface says it with extends:

Admin extends UserPop out in the code editor (opens in a new tab)TypeScript
interface User {  name: string;  email: string;} interface Admin extends User {  permissions: string[];} const lee: Admin = { name: "Lee", email: "lee@example.com", permissions: ["refunds"] };console.log(`${lee.name} can do: ${lee.permissions.join(", ")}`);

Lines 1 to 4 make User, with a name and an email. Line 6 makes Admin and says it extends User: an Admin has everything a User has. Line 7 adds what only admins have, a list of permissions (string[] is a list of strings). Line 10 makes Lee, who needs all three properties. Line 11 prints Lee can do: refunds.

Left, User has two cards: name: string and email: string. Plus, in the middle, a card permissions: string[] that Admin adds. An arrow leads to Admin on the right, with all three cards.Username: stringemail: string+Admin addspermissions: string[]Adminname: stringemail: stringpermissions: string[]interface Admin extends Useror: type Admin = User & { … }
Admin starts with everything User has, then adds permissions. An interface writes this with extends; a type alias writes it with &.

A type alias can't use extends. It builds on another type with &, which means "everything in this type and everything in that one". A type made with & is called an intersection:

The same Admin, built with &Pop out in the code editor (opens in a new tab)TypeScript
type User = {  name: string;  email: string;}; type Admin = User & {  permissions: string[];}; const lee: Admin = { name: "Lee", email: "lee@example.com", permissions: ["refunds"] };//    ^?console.log(`${lee.name} can do: ${lee.permissions.join(", ")}`);

Lines 1 to 4 are User as a type alias. Line 6 says an Admin is a User & the object type on lines 6 to 8, so it has a name, an email, and permissions. Line 10 makes the same Lee, the query on line 11 shows const lee: Admin, and line 12 prints the same Lee can do: refunds.

So far the two ways give the same result. They differ when the new type gets a property wrong. Below, User says a plan is "free" or "pro", and line 6 builds Admin on it. Press each button to change line 6:

Playground: build Admin on User
An admin built on a userPop out in the code editor (opens in a new tab)TypeScript
interface User {  name: string;  plan: "free" | "pro";} interface Admin extends User { permissions: string[] } const lee: Admin = { name: "Lee", plan: "pro", permissions: ["refunds"] };console.log(lee.name + " has " + lee.plan);
Console outputLee has pro
What happens
Line 6 usesinterface … extends
TypeScriptNo errors
Try it yourself

interface Admin extends User means an admin has everything a user has, plus permissions. Line 8 fits, and the code prints Lee has pro.

TypeScript checks the code for real each time you press a button. Each button changes only line 6. Reset goes back to extends.

extends and & have no errors. extends, plan: number gives plan a different type from the one User has, and TypeScript marks line 6 itself: Interface 'Admin' incorrectly extends interface 'User', which means "an Admin would no longer be a User". &, plan: number gets no error on line 6. No value can be a number and "pro" at once, so Admin becomes never, a type that no value fits, and the errors appear later, on lines 8 and 9, where the type is used. With extends, the error points at the real mistake. (The Intersection types lesson covers & in depth.)

An interface can also extend more than one type, and it can extend a type alias that names an object:

A customer built from two typesPop out in the code editor (opens in a new tab)TypeScript
type Contact = { email: string }; interface Address {  city: string;} interface Customer extends Contact, Address {  name: string;} const asha: Customer = { name: "Asha", email: "asha@example.com", city: "Pune" };console.log(`${asha.name} lives in ${asha.city}`);

Line 1 is a type alias, Contact, with an email. Lines 3 to 5 are an interface, Address, with a city. Line 7 says a Customer extends both, with a comma between them, and line 8 adds a name. Line 11 makes Asha with all three properties, and line 12 prints Asha lives in Pune. The two ways mix freely.

Which one to use

For most object shapes, you can use either one. A few things only one of them can do. You've seen the first: only a type alias can name a union, an exact value, or a simple type like string. The second is about declaring the same name twice. Two interfaces with the same name join into one:

Two Settings interfaces join into onePop out in the code editor (opens in a new tab)TypeScript
interface Settings {  theme: string;} interface Settings {  fontSize: number;} const settings: Settings = { theme: "dark", fontSize: 16 };console.log(settings.fontSize);

Lines 1 to 3 make a Settings interface with a theme. Lines 5 to 7 make another one with the same name and a fontSize. TypeScript joins them, so a Settings needs both. This is called declaration merging. Line 9 makes settings with both properties, and line 10 prints 16. Libraries use merging to let you add properties to their types; a later lesson, Declaration merging, shows how.

Two Settings type aliases (an error on purpose)Pop out in the code editor (opens in a new tab)TypeScript
type Settings = { theme: string };type Settings = { fontSize: number };

A type alias can't be declared twice. TypeScript marks both lines on purpose: Duplicate identifier 'Settings', which means "this name is already taken". An identifier is a name in your code.

Left: interface Settings twice, one with theme: string and one with fontSize: number. Arrows join them into one card with both properties, labelled merged into one. Right: type Settings twice, with the same two cards and the error Duplicate identifier 'Settings'.interface Settings, twicetheme: stringfontSize: numbertheme: string; fontSize: numbermerged into onetype Settings, twicetheme: stringfontSize: numberDuplicate identifier'Settings'an error on both lines
Declare an interface twice and TypeScript joins the two into one Settings with both properties. Declare a type twice and you get Duplicate identifier 'Settings'.

The table below sums up the differences. Read each row as a question, then the answer for each keyword.

type and interface, side by side
Questiontypeinterface
Can it name an object shape?Yes: type User = { name: string }.Yes: interface User { name: string }.
Can it name a union, an exact value, or a primitive?Yes: type Plan = "free" | "pro".No. An interface always describes an object shape.
How do you build on another type?With &: type Admin = User & { … }.With extends: interface Admin extends User { … }.
Where is a clashing property reported?Where you use the type, because the property, or the whole type, becomes never.On the interface line itself.
What if you declare the same name twice?An error: Duplicate identifier.The two declarations merge into one.
Is it there when the code runs?No. TypeScript removes it.No. TypeScript removes it.

The TypeScript handbook says you can mostly choose by taste, and suggests using interface until you need something only type can do. A simple rule that follows from the table:

  • Use interface for object shapes, especially ones you build on with extends, because a clash is reported where it happens.
  • Use type for everything an interface can't name: unions like "free" | "pro", and other names like Email.
  • Whatever you choose for objects, choose it the same way across a project, so readers aren't left wondering why.

Users and admins on an account page

Here is how the two work together on a real page. An account page shows a badge with each person's name, and adds (Pro) for pro users. Some people are admins:

An account page's types and badgePop out in the code editor (opens in a new tab)TypeScript
type Plan = "free" | "pro"; interface User {  id: number;  name: string;  plan: Plan;} interface Admin extends User {  permissions: string[];} function badge(user: User) {  return user.plan === "pro" ? `${user.name} (Pro)` : user.name;} const asha: User = { id: 1, name: "Asha", plan: "pro" };const lee: Admin = { id: 2, name: "Lee", plan: "free", permissions: ["refunds"] };console.log(badge(asha));console.log(badge(lee));

Line 1 uses a type alias for the plans, because it's a union. Lines 3 to 7 use an interface for a user, with an id, a name, and a plan. Lines 9 to 11 build Admin on User with extends. Lines 13 to 15 make the badge: line 14 adds (Pro) when the plan is "pro".

Line 17 makes Asha, a user, and line 18 makes Lee, an admin. Line 19 prints Asha (Pro). Line 20 passes Lee to badge, which asks for a User, and there's no error: an admin has everything a user has, so an admin fits wherever a user goes. It prints Lee.

Error or fine?
  • type Plan = "free" | "pro";
  • interface Plan = "free" | "pro";
  • interface User { name: string } const asha: User = { name: "Asha" };
  • type User = { name: string }; type User = { email: string };
  • interface User { name: string } interface User { email: string }
  • type Email = string; const email: Email = 7;
  • interface User { name: string } interface Admin extends User { name: number }
  • type User = { name: string }; interface Admin extends User { level: number }
Try it yourself
0 of 8 correct

Sort each line by what TypeScript says about it. Each line is checked on its own.

Choose a category for every card. You can change an answer at any time; Reset clears them all.

Common mix-ups

Type aliases and interfaces are only for TypeScript. Neither one becomes code that runs. Here is a small file with both:

profile.ts: a type alias, an interface, and an objectPop out in the code editor (opens in a new tab)TypeScript
type Plan = "free" | "pro"; interface User {  name: string;  plan: Plan;} const asha: User = { name: "Asha", plan: "pro" };console.log(asha.plan);

Line 1 is a type alias and lines 3 to 6 are an interface. Line 8 makes a real object, and line 9 prints pro. When TypeScript turns this into JavaScript, it removes the alias, the interface, and the : User annotation:

profile.js: what the browser getsPop out in the code editor (opens in a new tab)JavaScript
const asha = { name: "Asha", plan: "pro" };
console.log(asha.plan);

Only the object and the log are left, and the code still prints pro. You can't use User as a value, for example with typeof or instanceof, because it doesn't exist when the code runs.

A file profile.ts holds type Plan, interface User, const asha, and console.log. An arrow labelled types removed leads to profile.js, which holds only const asha and console.log.profile.tstype Plan = …interface User {…}const asha = {…}console.log(…)you write thistypes removedprofile.jsconst asha = {…}console.log(…)the browser runs this
You write profile.ts with a type alias and an interface. TypeScript removes both, so profile.js has only the object and the log. Nothing called Plan or User exists while the page runs.
  • "A type alias makes a new type." No. It's another name for the same type. Any string fits type Email = string, and hovering shows string.
  • "An interface checks objects more strictly than a type alias." No. For the same shape, both check the same way, and one can stand in for the other.
  • "Interfaces exist when the code runs, like classes." No. Both are removed. Nothing called User is left in profile.js.
  • "A type alias can't be extended." No. & builds on it, and an interface can use extends on a type alias that names an object, as Customer did with Contact.
  • "An interface can name any type." No. It always describes an object shape. For a union like "free" | "pro", use a type alias.
  • "A project must use only one of them." No. They mix freely: the account page uses a type alias for the plans and interfaces for the people.

Practice exercises

Each exercise is TypeScript. When you write or fix code, press Edit & run on the starter code: the errors update as you type, and the console shows what it prints. Try a guess first, then use the hints.

Exercise 1 · Warm-upFind the line TypeScript marks

Two products, one with a mistake. Which line will TypeScript mark?

Starter codePop out in the code editor (opens in a new tab)TypeScript
interface Product {
  name: string;
  price: number;
}

const tea: Product = { name: "Tea", price: 3 };
const cake: Product = { name: "Cake" };

Answer, then press Check. Spacing and letter case don’t matter.

    Exercise 2 · Warm-upName a repeated type

    The order's shape is written twice. Give it a name with a type alias and use the name in both places. What does your code print?

    Starter codePop out in the code editor (opens in a new tab)TypeScript
    function orderLabel(order: { id: number; city: string }) {  return `Order ${order.id} to ${order.city}`;} const first: { id: number; city: string } = { id: 7, city: "Pune" };console.log(orderLabel(first));

    Answer, then press Check. Spacing and letter case don’t matter.

      Exercise 3 · PracticeWrite the missing interface

      greet uses a User type that doesn't exist yet. Write it as an interface. What does the fixed code print?

      Starter codePop out in the code editor (opens in a new tab)TypeScript
      function greet(user: User) {  return `Hi, ${user.name}! You have ${user.cartItems} items.`;} console.log(greet({ name: "Asha", cartItems: 2 }));

      Answer, then press Check. Spacing and letter case don’t matter.

        Exercise 4 · PracticeGive the admin what a user needs

        TypeScript marks line 10. Fix it. Which property did you add?

        Starter codePop out in the code editor (opens in a new tab)TypeScript
        interface User {  name: string;  email: string;} interface Admin extends User {  permissions: string[];} const lee: Admin = { name: "Lee", permissions: ["refunds"] };console.log(lee.email);

        Answer, then press Check. Spacing and letter case don’t matter.

          Exercise 5 · ChallengeFind the second declaration

          Line 5 looks like it matches Settings, but TypeScript marks it. Which property does it say is missing, and where does that property come from?

          Starter codePop out in the code editor (opens in a new tab)TypeScript
          interface Settings {
            theme: string;
          }
          
          const settings: Settings = { theme: "dark" };
          
          interface Settings {
            fontSize: number;
          }

          Answer, then press Check. Spacing and letter case don’t matter.

            Exercise 6 · ChallengeMake room for a team plan

            The shop adds a team plan, and TeamUser on line 8 gets an error. Fix it by changing one line. Which value do you add to Plan?

            Starter codePop out in the code editor (opens in a new tab)TypeScript
            type Plan = "free" | "pro"; interface User {  name: string;  plan: Plan;} interface TeamUser extends User {  plan: "team";  seats: number;}

            Answer, then press Check. Spacing and letter case don’t matter.

              Check your understanding

              For each question, ask what each name means: which properties or values it allows, and whether it's still there when the code runs. The quiz shows its code without the checker, so the error list doesn't give the answers away.

              The type aliases and interfaces quiz · 7 questionsScore: first tries count
              1. Question 1 of 7What does type Product = { name: string; price: number } make?

                Choose an answer to see the explanation.

              2. Question 2 of 7Which of these can an interface name?

                Choose an answer to see the explanation.

              3. Question 3 of 7Two interfaces share a name. What does TypeScript say about line 4?

                Read the code, then predictPop out in the code editor (opens in a new tab)TypeScript
                interface Settings { theme: string }
                interface Settings { fontSize: number }
                
                const settings: Settings = { theme: "dark" };

                Choose an answer to see the explanation.

              4. Question 4 of 7Which line does TypeScript mark in this extends?

                Read the code, then predictPop out in the code editor (opens in a new tab)TypeScript
                interface User { name: string; plan: "free" | "pro" }
                interface Admin extends User { plan: number }
                const lee: Admin = { name: "Lee", plan: 1 };

                Choose an answer to see the explanation.

              5. Question 5 of 7What does hovering email on line 2 show?

                Read the code, then predictPop out in the code editor (opens in a new tab)TypeScript
                type Email = string;
                const email: Email = "asha@example.com";

                Choose an answer to see the explanation.

              6. Question 6 of 7This code has a type error. What does it print when it runs anyway?

                Read the code, then predictPop out in the code editor (opens in a new tab)TypeScript
                interface User { name: string }
                const kind = typeof User;
                console.log(kind);

                Choose an answer to see the explanation.

              7. Question 7 of 7Can an Admin go where a User is expected, and what prints?

                Read the code, then predictPop out in the code editor (opens in a new tab)TypeScript
                interface User { name: string }
                interface Admin extends User { permissions: string[] }
                
                function greet(user: User) {
                  return `Hi, ${user.name}`;
                }
                
                const lee: Admin = { name: "Lee", permissions: [] };
                console.log(greet(lee));

                Choose an answer to see the explanation.

              Key takeaways

              • A type alias, type Product = …, gives any type a name: an object, a union, or a simple type like string.
              • An interface, interface User { … }, gives an object shape a name.
              • Write a type once and use its name everywhere. One change is then checked at every use.
              • Build on a type with interface Admin extends User or type Admin = User & { … }. extends reports a clash on the interface itself.
              • Interfaces with the same name merge; type aliases with the same name are an error.
              • Neither is there when the code runs, and an alias is never a new type, just a second name.

              Remember the one-liner.
              Name a type once and use the name everywhere: type for any type, interface for object shapes you build on.

              Coming next: null, undefined & strictNullChecks. It shows how TypeScript makes you handle a value that might be missing, like a user with no nickname.

              CompleteFrontend Clear concepts. Working examples.