Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

Constrain type to keys of array but respect length

I have an array and I want to get a type which constrains its possible values to just valid keys. I thought that keyof typeof array would solve this, but it accepts all numbers.

const arr = ["a", "b", "c"] as const

type keyOfArr = keyof typeof arr // Does not work work. Accepts all numbers

let x: keyOfArr = 1    ✔️ Should work
let x: keyOfArr = 2    ✔️ Should work
let y: keyOfArr = -1   ❌ Should not work
let z: keyOfArr = 999  ❌ Should not work

>Solution :

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

You need recursively iterate through the List and incrementaly add length to accumulator:

const arr = ["a", "b", "c"] as const

type List = (typeof arr)

type AllowedIndexes<T extends readonly any[], Result extends any[] = []> =
    T extends readonly [infer _, ...infer Rest]
    ? AllowedIndexes<Rest, [...Result, Result['length']]>
    : Result[number]


type Result = AllowedIndexes<List>

let x: Result = 1   // ok
let xx: Result = 2   // ok
let y: Result = -1  // error
let z: Result = 999 // error

Playground

Since TypeScript 4.8, it is doable without recursion:

const arr = ["a", "b", "c"] as const

type List = (typeof arr)

type ParseInt<T> = T extends `${infer Digit extends number}` ? Digit : never

type AllowedIndexes<T> =
    {
        [Prop in keyof Omit<T, number>]:
        (Prop extends `${number}`
            ? ParseInt<Prop> : never)
    }[keyof Omit<T, number>]

type Result = AllowedIndexes<List>

let x: Result = 1   // ok
let xx: Result = 2   // ok
let y: Result = -1  // error
let z: Result = 999 // error

Thanks to this PR, it is possible to infer numeric value from template string.
It works only in TS nightly.

Playground

Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading