Reputation: 44436
Here is what I want:
interface ValidValues {
TOP: number;
BOTTOM: number;
}
function f(b: valuesof(ValidValues)) {
}
function g(valid: ValidValues) {
f(valid.TOP);
f(3); // should not compile
}
Even though it's not impossible that 3 happens to equal valid.TOP or valid.BOTTOM, since it cannot be demonstrated at compile-time, I want it to err out.
Possible?
Yes, I know nothing stops a user from constructing his own implementation of ValidValues with TOP or BOTTOM set to 3. I am in this situation where a Javascript library is giving my a function and giving me a object full of values to call it with, and I'm trying to type it in Typescript.
Upvotes: 1
Views: 668
Reputation: 330336
It looks like you want something like branded primitives to have a type ValidValue
which is assignable to number
but is not assignable from number
. This is a trick where you intersect number
with an object type containing a "brand" property so the compiler can tell the difference between a plain number
and a branded ValidValue
, even though at runtime there is no difference (a ValidValue
will not really have the brand property at runtime).
Something like this:
type ValidValue = number & { __brand: "ValidValue" };
interface ValidValueObj {
TOP: ValidValue;
BOTTOM: ValidValue;
}
Let's see how it works:
function f(b: ValidValue) {}
function g(valid: ValidValueObj) {
f(valid.TOP);
f(3); // error as desired
}
And if you want to force the compiler to accept a number
as ValidValue
you can use type assertions:
function getValidValueObj(top: number, bot: number): ValidValueObj {
return {
TOP: top as ValidValue,
BOTTOM: bot as ValidValue
};
}
Does that help? Good luck!
Upvotes: 2
Reputation: 276343
Possible
No. Not with the interface:
interface ValidValues {
TOP: number;
BOTTOM: number;
}
Anything that accepts values from ValidValues
will accept any number
(like 3
)
Upvotes: 0