Reputation: 903
I want to use generics to decrease maintenance, and possible chance of errors while maintaining, Typescript types.
I have a function called loadValues
that takes in an object with the following example interface:
interface DashboardPreload: {
studentNames: Observable<string[]>,
seatNumbers: Observable<number[]>
}
And returns an object with the following, very similar, interface. Note it has the same keys, and keys have the same values, except in DashboardPreload, it's wrapped in an Observable:
interface DashboardState: {
studentNames: string[],
seatNumbers: number[]
}
So specifying the types look like this:
function loadValues(preload: DashboardPreload): DashboardState {
// ...
}
To reuse the loadValue
function across components, I've changed the signature to allow for generics:
loadValues<A, B>(preload: A): B {
// ...
}
state = loadValues<DashboardState, DashboardPreload>(toPreload);
// another component would then do
interface UserDetailPreload: {
name: Observable<string>;
address: Observable<string>;
}
interface UserDetailState: {
name: string;
address: string;
}
otherState = loadValues<UserDetailState, UserDetailPreload>(otherValuesToPreload);
But there is a massive win I still want to take. My input and output objects
To avoid having to maintain very similar types, it would be great if generics could specify the above relationship between the input and output types. I want to simply provide a single generic parameter (e.g the output) and the signature is written in a way that will type the input and output:
// How should this signature look?
function loadValues<P>(preload: ?): P {
// ...
}
state = loadValues<DashboardState>(toPreload);
Is this possible? How should the function signature look (please note I'm not asking for the logic in the function, but asking how to do the generics). I've looked at e.g.
but haven't found a solution.
Upvotes: 0
Views: 2161
Reputation: 366
you can add a Preload type like this:
type Preload<T> = {
[P in keyof T]: Observable<T[P]>;
};
function loadValues<P>(preload: Preload<P>): P {
// ...
}
state = loadValues<DashboardState>(toPreload);
Upvotes: 1
Reputation: 5684
I'm not exactly certain I understand what you're trying to achieve, so this might not pose a complete answer, but perhaps this might push you in the right direction.
If you make the type of your preload
argument generic as well, typescript should be able to infer the generic return type. You'd need to introduce a new generic interface for this.
So your function signature would look like this:
function loadValues<P>(preload: PreloadState<P>): P {
// ...
}
interface PreloadState<P> { }
and when you use it like this
var preload: PreloadState<DashboardState> = { .. };
var result = loadValues(preload);
the type of result
will correctly be inferred to be of type DashboardState
.
Upvotes: 0