5

I want to define an interface which has a key whose value can be an array of strings. but those strings can only be from a defined array of strings.

Something like -

const valueOptions = ['a', 'b', 'c', .... 100 more];

interface containerProps {
  key: <array of strings which can only be a subset of valueOptions>
}

Please help.

ghostCoder
  • 1
  • 9
  • 49
  • 72
  • 3
    Just to be clear, do you want your `key` property to be a subset of your array or the key itself ? if so, you can check out [this answer](https://stackoverflow.com/a/45257357/5784924) – Nicolas Nov 14 '19 at 16:03
  • not they key. key is a fixed string. i want the value of that key to be an array which is a subset of valueOptions – ghostCoder Nov 14 '19 at 16:15

3 Answers3

2

First lock down your array items using <const> assertion so they are the limited set.

Now you can play with type of index values. e.g.:

  • typeof valueOptions[0] can only be "a"
  • typeof valueOptions[1] can only be "b"
  • typeof valueOptions[number] can be either of "a", "b", "c"

So for your context you would use number as you are not looking for any specific index:

const valueOptions = <const>["a", "b", "c"]; // lock it down with const assertion

interface IContainerProps {
  key: typeof valueOptions[number]; // typeof index members of valueOptions
}

const a: IContainerProps = {
  key: "b"
};

So for small subsets you can create a union type:

interface IContainerProps {
  key: typeof valueOptions[1] | typeof valueOptions[2];
}

const a: IContainerProps = {
  key: "b"
};

const b: IContainerProps = {
  key: "c"
};
makeitmorehuman
  • 11,287
  • 3
  • 52
  • 76
1

You can extract the type and then map it onto your interface like so

// declare "as const" to make it a readonly Array<"a"|"b"|"c"> instead of string[]
const valueOptions = ["a", "b", "c"] as const;

// Type helper to extract the underlying data type of the array
type StripArray<T extends ReadonlyArray<string>> = T extends ReadonlyArray<infer U> ? U : never; 

type ValueUnion = StripArray<typeof valueOptions>; // ValueUnion = "a"|"b"|"c";

interface Whatever {
    keys: ValueUnion[] // Whatever.keys is Array<"a"|"b"|"c">
}

I do a lot of this kind of stuff on the TS playground page, it's extremely helpful for quickly looking at types and seeing what's actually happening.

http://www.typescriptlang.org/play/?ssl=1&ssc=1&pln=11&pc=2#code/PTAEBMFMGMBsEMBOlQCJ4GdTQPYDsMAXVUQnUAW3gGsUBLQ0eUZecfWAT1AEFFF4nADzpUAH1QAjcamioAfKDoFCkNqBwAzUEUTKA5gG0AugChcK0ADd4sAK6QA8gAdCdfFgC8oQ6IA0aNIBsqjGTFgWRADcpqYgoAAqnM4oABaQsCmIpOSQAB6EAtCMhOmgdnhQiFwGEPCEzITJKFqkZUgCnKZNKaAAyoV0znydQgmg+aqVWABKaux4XCOCQroG8ore45OQ06BzbBycy8LKmpDZAKqKAPygl6AAXKB4kFYXUaCxPSgAarYOS54dx4UDeAZ6Yb8FY-Vo2exOVwgjDyT7xf4IoEgsFoeAyaQSOQxUzKVSITTwaAoADqqXqbwuoAA3qZQGzQLROBhnhjAcD8CZQPFafT3ogAHScrB0LAnER4iQEkLyUwAXyAA

CollinD
  • 7,304
  • 2
  • 22
  • 45
0
enum KeyOptions {

 A = ‘a’,
 B = ‘b’

}

interface ArrayAndStuff {

 key: KeyOptions[];

}
Ernesto
  • 3,944
  • 1
  • 14
  • 29
  • 3
    While this code may answer the question, providing additional context regarding why and/or how this code answers the question improves its long-term value. – jrook Nov 14 '19 at 18:53