网站搜索

在 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. 用开头的 null 填充 Tuple 并记录最后推入的值时,我的方法是使用一个长度为 Start 的 TempTuple,并随着 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];
}

操场