Reputation: 22375
In typescript I would like to have a function, like
getMin<T>(a: T, b: T): T
Which will return either a, or b such that, if a < b
getMin(a, b) === a
Is always true. For example, the following function would not qualify:
const getMin = (a: IUser, b: IUser): IUser => {
if (min(a.userId, b.userId) === a) {
return new User(a); // copy constructor
} else {
return new User(b);
}
}
Because getMin(a, b) === a
will return false
since a
is not referentially equal to the return value of getMin
. This is because getMin
returns a copy of a
, not the a
that was passed into the function. What I want is a function that returns either of its inputs, something like,
const getMin = (a: IUser, b: IUser) => {
if (min(a.userId, b.userId) === a) {
return a; // reference
} else {
return b;
}
}
That way, if I wrote a function that was accidentally creating a copy when I wanted it to return one of the given references, it would be a compile time error. I'm imagining a type signature like,
getMin<T>(a: T, b: T): a | b
Similar to how we can do,
getThreeOrFive (): 3 | 5
It seems like the this
keyword already works this way in TS, since I can write a function like,
this.doSomething = (): this => { /* does something */ return this }
Is there some way to do this in TS?
Upvotes: 0
Views: 44
Reputation: 250972
My understanding is that you want to guarantee that one of the inputs is returned as the output - not just a matching type.
I don't believe a type system can do this for you, but a good unit test can.
I have written the test without a framework for demonstration purposes - but you can see that a unit test around this would prevent a new instance from being returned:
interface IUser {
userId: number;
}
class User implements IUser {
userId: number;
constructor(u: IUser) {
this.userId = u.userId;
}
}
const getMinA = (a: IUser, b: IUser): IUser => {
if (a.userId < b.userId) {
return new User(a); // copy constructor
} else {
return new User(b);
}
}
const getMinB = (a: IUser, b: IUser): IUser => {
if (a.userId < b.userId) {
return a;
} else {
return b;
}
}
const a = new User({ userId: 1 });
const b = new User({ userId: 2 });
if (getMinA(a, b) === a) {
// Okay
} else {
alert('getMinA: Not original A');
}
if (getMinB(a, b) === a) {
// Okay
} else {
alert('getMinB: Not original A');
}
The output from this is:
getMinA: Not original A
Upvotes: 3