Υπάρχει τρόπος να δηλώσετε μια διαδοχική ένωση λεκτικών συμβολοσειρών στο Typescript


Θέλω να δηλώσω έναν τύπο ένωσης κυριολεκτικών συμβολοσειρών: "10" | "11" | ... | "99".

Σκέφτηκα μια λύση για να παρακάμψω το πρόβλημα, αλλά δεν δούλεψε

const arr = Array.from({
  length: 90
}, (_, i) => i + 10) as const; // expected arr type is readonly [10, 11, ..., 99]
// If above works, then
type NumberToString<T extends number> = `${T}`;
type Successive = NumberToString<typeof arr[number]>;

Αναρωτιέμαι αν υπάρχει τρόπος να ορίσω γρήγορα το "10" έως "99" πάνω από το επίπεδο τύπου;

Απάντηση #1

Αυτό θα πρέπει να είναι δυνατό στην επόμενη έκδοση (4.5) του TypeScript όπου το όριο βάθους δημιουργίας τύπων θα πρέπει να αυξηθεί

type _NextValue<From, LastValue, R extends any[]> = LastValue extends number 
    ? R['length'] 
    : R['length'] extends From ? From : null

/**
 * Fill array with `null` placeholders until index `From`
 * Then append array length as a member until getting to `To` length
 * Example: `_Values<5, 11>` will result in `[null, null, null, null, null, 5, 6, 7, 8, 9, 10]`
 */

type _Values<From, To, R extends any[] = [], LastValue = null> = R['length'] extends To ? R : 
    _Values<
        From, 
        To, 
        [...R, _NextValue<From, LastValue, R>], 
        _NextValue<From, LastValue, R>
    >

/**
 * Exclude nulls and convert to strings
 */
type NumbersToStrings<T extends Array<number | null>> = `${NonNullable<T[number]>}`;

type N10_99 = NumbersToStrings<_Values<10, 100>> // "10" | "11" | "12" | "13" | "14" | "15" | ... | "99"

Παιδική χαρά

Απάντηση #2

Βρήκα μια διαφορετική προσέγγιση για να λύσω αυτή την ερώτηση, ενώ ο @Aleksey L. γεμίζει το Tuple με αρχικά null και καταγράφει την τελευταία ανασυρόμενη τιμή, η δική μου προσέγγιση είναι να χρησιμοποιήσω ένα TempTuple του οποίου το μήκος είναι Start και μεγαλώνει καθώς μεγαλώνει το ResTuple.

type AddOne<T extends number, Tuple extends unknown[] = []> = 
    Tuple["length"] extends T ? [1, ...Tuple]["length"] : 
        AddOne<T, [1, ...Tuple]>; 

/** fill tuple to a fixed length */
type FillTuple<T extends number, Tuple extends unknown[] = []> = 
    Tuple["length"] extends T ? Tuple : 
        FillTuple<T, [1, ...Tuple]>; 

/** TempTuple is meant to grow as ResTuple grow */
type RangeTuple<Start extends number, End extends number, ResTuple extends unknown[] = [], TempTuple extends unknown[] = FillTuple<Start>> =
    TempTuple["length"] extends AddOne<End> ? ResTuple : 
        RangeTuple<Start, End, [...ResTuple, `${TempTuple["length"]}`], [1, ...TempTuple]>;

{
    type _ = RangeTuple<10, 99>[number];
}

παιδική χαρά