Shaun
Shaun

Reputation: 2052

Using TypeScript Generic Interfaces

I have several types of objects, like articles, divisions, profiles, etc. I defined an interface for each, basically:

interface IArticle {
    title: string;
    body: string;
}

interface IProfile {
    name: string;
    email: string;
}

interface IDivision {
    name: string;
    leader: IProfile;
}

Now I want to, in some cases, be able to add a formTitle property when using these on a page that displays a form. I thought I could do something like this:

// Failed
interface IForm<T> {
    formTitle: string;
}

function formDisplay(resource: IForm<IProfile>) { }

But when I do that, I get an error indicating the object properties (name and email, in this case) do not exist on type IForm<IProfile>. So I guess this is not the correct use of generics. Coming from Ruby and JavaScript, I'm still new to the whole static typing thing.

To get around this, I have been writing separate interfaces for each object, like this:

// Not reusable
interface IArticleForm extends IArticle {
    formTitle: string;
}

Another alternative I could think of would be to add an optional property to a base interface and then extend the regular object interfaces from there.

// Does not provide helpful type checking
interface IBase {
    formTitle?: string;
}
interface IArticle extends IBase { }

But I want formTitle to be required on these form pages so that I don't forget to set it. Is there some way to apply a group of required properties to multiple objects in a reusable way?

Upvotes: 2

Views: 1899

Answers (3)

shahul01
shahul01

Reputation: 349

You should use Type inside the interface to have effect...


interface IObject<Type> {
  [x:string]: Type;
};

const stringObj:IObject<string> = {
  a: 'b',
  c: 1 // will give error
}

const anyObj:IObject<string|number> = {
  a: 'b',
  c: 1 // no error
}

Upvotes: 0

Tadwork
Tadwork

Reputation: 174

Looks like you are looking for Intersection Types. this allows you to mix to behaviors together. You can even alias the newly created type to give it a convenient name that describes its usage.

For your example use:

interface IProfile {
    name: string;
    email: string;
}
interface IForm {
    formTitle: string;
}
type IProfileForm = IForm & IProfile;

function formDisplay(resource: IProfileForm) { }

Upvotes: 5

mk.
mk.

Reputation: 11710

Generics are intended to "contain" whatever type is generic - you need a field in your IForm that is of your generic type:

interface IMyContent {}

interface IProfile extends IMyContent {
    name: string;
    email: string;
}

interface IForm<T extends IMyContent> {
    formTitle: string;
    content: T;
}

var x : IForm<IProfile> = {
    formTitle: "",
    content: {name: "", email: ""}
}

Upvotes: 3

Related Questions