Michael Lorton
Michael Lorton

Reputation: 44436

Can I restrict a type to values of an Interface?

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

Answers (2)

jcalz
jcalz

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!

Link to code

Upvotes: 2

basarat
basarat

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

Related Questions