Home > Software design >  Typescript nest types and interfaces, for better organization
Typescript nest types and interfaces, for better organization

Time:10-26

Is there a way to nest types and interfaces for better organization?

eg. let myshark: Animals.Fish.Shark

To allow referring the nested Shark interface, what kind of implementation structure of the interfaces work?

One attempt could be =>

interface Animals{

    interface Mamals{

        interface Bat {
            kind:string;
            wings:number;
        }
    }
    
    interface Fish {
        
        interface Shark {
            variant:string;
            color:string;
            fins:number;
        }
    }
}

To then use them as follows

let greatwhite: Animals.Fish.Shark;
let mybat: Animals.Mamals.Bat;

I have also tried using classes and namespaces? Is there a proper way to do this or is it not possible to get type declarations such as let myshark: Animals.Fish.Shark?

CodePudding user response:

If you don't want to use separate modules for each namespace, you could use TypeScript-specific namespaces. Either you can define them directly so that Animals is an actual object at runtime that can hold properties as well as types (and you need to remember to export anything you want visible from the outside):

namespace Animals {
    export namespace Mammals {
        export interface Bat {
            kind: string;
            wings: number;
        }
    }
    export namespace Fish {
        export interface Shark {
            variant: string;
            color: string;
            fins: number;
        }
    }
}

Or you can just declare the namespace and then anything mentioned within is automatically treated as exported (since otherwise they just wouldn't be declared):

declare namespace Animals {
    namespace Mammals {
        interface Bat {
            kind: string;
            wings: number;
        }
    }
    namespace Fish {
        interface Shark {
            variant: string;
            color: string;
            fins: number;
        }
    }
}

Either way you will then be able to refer to the nested interfaces via dot notation, as desired:

let greatwhite: Animals.Fish.Shark; // okay
let mybat: Animals.Mammals.Bat; // okay

Playground link to code

CodePudding user response:

Yes this is (partly) possible with namespace, see Docs. Though I suspect you may not be happy with the fact you cannot nest namespace objects in one another without getting an error:
"A 'declare' modifier cannot be used in an already ambient context.(1038)"

I personally have never done this as I don't (yet) see the benefit to it.

declare namespace GreetingLib {
  interface LogOptions {
    verbose?: boolean;
  }
  interface AlertOptions {
    modal: boolean;
    title?: string;
    color?: string;
  }
}

// Usage example
const aVariable: GreetingLib.LogOptions = {};
const anotherVariable: GreetingLib.LogOptions = {
  verbose: false,
};
const someVariable: GreetingLib.LogOptions["verbose"] = false;

Note: you would have to initiate your variables with some kind of value. TypeScript will not simply let you initiate these without providing some kind of value (e.g. const aVariable: GreetingLib.LogOptions = {};)

In my opinion

I would much prefer the use of extending the types based on some kind of mutual properties:
"kingdom": "Plantae" | "Animalia" | ... ,

  • Related