The source code for this blog is available on GitHub.
Note
Top

Type, Declare, and Interface in TypeScript

Cover Image for Type, Declare, and Interface in TypeScript
Han Chen
Han Chen

The difference between type and interface

type and interface are two key concepts in TypeScript that allow you to describe the structure of complex data types, such as objects and arrays. While they are similar in some ways, they are also distinct in their use cases and how they are implemented in the language.

Here are the main differences between type and interface in TypeScript:

  1. Syntax: The syntax for defining a type and an interface is different, with type being a simpler syntax and interface being more flexible and powerful.
  2. Structural typing: interface uses structural typing, meaning that two objects are considered compatible if they have the same structure, regardless of their names. On the other hand, type uses nominal typing, meaning that two objects must have the same name in order to be considered compatible.
  3. Merging: interfaces can be merged in TypeScript, which allows you to combine multiple interfaces into a single type. Types, on the other hand, cannot be merged in the same way.
  4. Declaration: type is used for type aliases, while interface is used for interfaces.
  5. Usage: interfaces are typically used to define the structure of objects, while types are used for a wider range of purposes, including type aliases, unions, and intersections.

In general, it's best to use interface when you want to describe the structure of objects and type when you need to create more complex data types.

In my project, I always use either type or interface within a component. For example, in the code snippet below, the IbpHeadProps is declared as a type with optional properties size and className. This type is then used as the type of the function component's props.

import React from "react";

// Use either `type` or `interface` is fine
type IbpHeadProps {
  size?: number;
  className?: string;
}

export default function IbpHead({ size, className }: IbpHeadProps) {
  return (
    <svg
      xmlns="http://www.w3.org/2000/svg"
      width={size || 50}
      height={size || 50}
      viewBox="0 0 241.188 139.874"
      className={`h-auto ${className || ""}`}
    >
      ...
      </g>
    </svg>
  );
}

In my project, I utilize interface within my types folder to provide a more structured type definition

In TypeScript, interfaces are used to provide a more structured type definition. In a project, they are typically stored within a types folder.

Simple Interface Usage

Here is an example of how you can define and use interfaces in TypeScript:

// types/user.ts
export interface User {
  id: number;
  name: string;
  email: string;
  password: string;
}

// types/post.ts
export interface Post {
  id: number;
  title: string;
  content: string;
  authorId: number;
}

// types/comment.ts
export interface Comment {
  id: number;
  content: string;
  postId: number;
  authorId: number;
}

Each interface defines the shape of a type. For example, User has id, name, email, and password properties. These interfaces can be imported and used in other parts of your codebase.

Namespaced Interfaces

You can also wrap your interfaces in a namespace to avoid naming collisions and make the code easier to organize. Here's an example:

declare namespace Types {
  // types/user.d.ts
  export interface User {
    id: number;
    name: string;
    email: string;
    password: string;
  }

  // types/post.d.ts
  export interface Post {
    id: number;
    title: string;
    content: string;
    authorId: number;
  }

  // types/comment.d.ts
  export interface Comment {
    id: number;
    content: string;
    postId: number;
    authorId: number;
  }
}

// main.d.ts
namespace MyApp {
  export import User = Types.User;
  export import Post = Types.Post;
  export import Comment = Types.Comment;
}

In this example, all the interfaces are defined within the Types namespace. The main.ts file then re-exports the interfaces under the MyApp namespace. Now, when you import the interfaces in other parts of your code, you can use MyApp.User, MyApp.Post, and MyApp.Comment.

declare and declared ts extension

In TypeScript, declare namespace and namespace have different purposes.

declare namespace is used to declare a new namespace in a separate .d.ts declaration file, with the intention that this namespace will be merged with a namespace declared elsewhere, either in another .d.ts file, or in the main code. The declare keyword is used to indicate that this is just a declaration, not a definition.

// types.d.ts
declare namespace MyNamespace {
  export interface MyType {
    ...
  }
}

On the other hand, namespace is used to create a new namespace in the main code. This namespace can contain both types and values, and can be used to organize your code into logical units.

// main.ts
namespace MyNamespace {
  export interface MyType {
    ...
  }

  export const myValue: MyType = ...;
}

So, in essence, declare namespace is used to augment existing namespaces from other files, while namespace is used to create a new namespace from scratch within a single code file.

Here is a comprehensive explanation of the difference between the .d.ts and .ts syntax in TypeScript.

Does import have to do with namespace

The import statement has no relationship with declare namespace or namespace in TypeScript. The import statement has no connection with declare namespace or namespace in TypeScript.

They serve different purposes.

the import statement is not used with declare namespace. The declare namespace is a way to declare a namespace in TypeScript, which allows you to group together values, functions, and objects under a common name. This can be useful for organizing your code and avoiding naming collisions with other code in your application.

The import statement is used to include exports from another module into your current module, while declare namespace is used to define a namespace in TypeScript. The two are not related and are used for different purposes.

Here is an example of a declare namespace:

declare namespace MyModule {
  export interface MyInterface {
    // properties and methods
  }

  export function myFunction(): void;
}

And here is an example of an import statement:

import { myModuleFunction } from './myModule';

How to extend type

The above code examples demonstrate two different ways to extend a type in TypeScript: using the type keyword, and using the interface keyword.

In the first example, the type CategoryWithProductsProps is being defined as a combination of two existing types, Category.GetCategoryResponse and an object with a property products that is an array of Product objects. This results in a new type that has all of the properties of Category.GetCategoryResponse and an additional property products of type Product[].

In the second example, the interface keyword is used to extend the GetProductResponse type. The GetProductResponseWithCategories interface is defined as having all of the properties of the GetProductResponse type, with the addition of a property categories of type number[].

Both the type and interface keywords can be used to extend a type in TypeScript, but the interface keyword is more commonly used for this purpose, as it provides more flexibility in defining the properties and methods of the new type.

// for reserve word `type`
type CategoryWithProductsProps = Category.GetCategoryResponse & {
  products?: Product[];
};

// for reserve word `interface`
interface GetProductResponseWithCategories extends GetProductResponse {
  categories: number[];
}

When two key types are identical, you can simply use a blank type instead of repeating it. For instance, the ShippingAddress interface in the following example is the same as the BillingAddress interface

export interface ShippingAddress extends BillingAddress {}

export interface BillingAddress {
  first_name: string;
  last_name: string;
  company: string;
  street_1: string;
  street_2?: string | undefined;
  city: string;
  state: string;
  zip: string;
  country: string;
  country_iso2: string;
  phone: string;
  email: string;
  form_fields?: any[];
}
© 2024 WOOTHINK. All Rights Reserved.
Site MapTerms and ConditionsPrivacy PolicyCookie Policy