Reputation: 8316
In a project that includes several front-end apps and several tens of microservices we have a private npm repository that contains some "commons" for those front-end apps. Naturally, commons include some models in TS, like
interface IUser {
id: string;
login: string;
name: string;
...
}
This is fine for the apps to be "on the same page"; however, in rapid development all microservices don't necessarily return the same model in their API responses. Like some microservice may return an object that's "enriched" compared to the interface in commons:
interface IUser {
id: string;
login: string;
name: string;
...
extraField1: someType1;
extraField2: someType2;
}
Enriched types can be easily defined via another interface which extends the one from commons:
interface IUserEnriched extends IUser {
extraField1: someType1;
extraField2: someType2;
}
and that is used from time to time outside commons. But there also are cases where a microservice returns an "impoverished" object:
interface IUserImpoverished {
id: string;
/* no login: string; here; or may be it's optional, unlike in the common interface */
name: string;
...
}
I wonder if TypeScript has some way to "deduce" such an interface from IUser
instead of duplicating code (?). This case is actually more problematic in terms of updating commons: if we change IUser
in commons by adding some fields, it is unlikely that any app won't get built (at least when we read data from API), it's just we don't use those new properties; on the contrary, if one changes IUser
in commons by removing the login
property, they also will need to create "enriched" interfaces in each app that actually uses login
. So it's really desirable to be able to "impoverish" interfaces too.
I've tried to google using keyword "narrow [TS interface]" but narrowing is a term used to describe a different case. May be you know the correct term – if so, please share.
Upvotes: 0
Views: 101
Reputation: 327704
You can use the Omit<T, K>
utility type to "impoverish" object types T
by removing properties with keys of type K
this way. You can make a type alias:
type TUserImpoverished = Omit<IUser, "login">;
or, if you need an interface:
interface IUserImpoverished extends Omit<IUser, "login"> { }
Note that the second parameter to omit is the string literal type "login"
. You can see that the omitted key is removed from the known keys of the resulting object type:
const impoverishedUser: IUserImpoverished = { id: "1", name: "Alice" };
Note that if you want to remove more than one key you can do it by specifying that K
is a union of the relevant key types:
type TUserFurtherImpoverished = Omit<IUser, "login" | "name">;
const furtherImpoverishedUser: TUserFurtherImpoverished = { id: "2" };
Okay, hope that helps; good luck!
Upvotes: 1
Reputation: 198
I'm not sure I understand your use case but you can juggle utility types like so:
interface IUser {
id: string;
name: string;
}
type IUserImpoverished = Pick<IUser, 'id'>;
const impoverishedUser: IUserImpoverished = {
id: 'meh'
};
Upvotes: 1