Reputation: 2052
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
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
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
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