如何为具有相似名称的变量列表创建typescript接口?



我想声明一个接口,该接口具有许多具有相似名称的变量,并且我不想手动创建它。类型为

interface {
"Var 1": string;
"Var 2": string;
"Var 3": string;
"Var 4": string;
"Var 5": string;
}

这个列表最多可以有55个,所以不可能把所有的变量名都写在接口中。

您可以使用模板文字类型将数字类型的联合转换为您正在寻找的那种键。假设您有一个名为VarRange的类型,其形式如下:

type VarRange = 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 
| 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20
| 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 
| 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40
| 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 
| 51 | 52 | 53 | 54 | 55

那么你可以把你的接口写成

interface VarInterface extends Record<`Var ${VarRange}`, string> { }

并验证它是否按预期工作

declare const vi: VarInterface;
vi["Var 51"] = "okay"
vi["Var 99"]; // error

不幸的是没有内置的方法很容易地创建VarRange;如果你能写type VarRange = 1 .. 55就好了,但是TypeScript不支持TypeScript 4.4这样的东西。在microsoft/TypeScript#15480中有一个开放的特性请求来实现这样的范围类型,但目前还不存在。

所以你可以使用上面的硬编码列表就像我,或者你可以写一些更复杂的类型操作使编译器尝试为你找出答案。在TypeScript 4.5中,他们将取消语言中的一些递归限制,你可以这样做:

type TupleOf<N extends number, T = any, R extends T[] = []> =
R['length'] extends N ? R : TupleOf<N, T, [T, ...R]>
type VarRange = Exclude<keyof TupleOf<56>, "0" | keyof any[]>
/* type VarRange = "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9" | "10" |
"11" | "12" | "13" | "14" | "15" | "16" | "17" | "18" | "19" | "20" | "21" |
"22" | "23" | "24" | "25" | "26" | "27" | "28" | "29" | ... 25 more ... | "55" */
interface VarInterface extends Record<`Var ${VarRange}`, string> { }

,它使用递归条件类型和可变元组类型构建一个长度为56的元组,并获取它的所有类似数字的键(不包括"0")。


对于TS4.1到TS4.4,你仍然可以这样做,但它甚至更复杂,因为递归限制太浅,无法达到55。比如:

type Length7 = [0, 0, 0, 0, 0, 0, 0];
type Length14 = [...Length7, ...Length7];
type Length28 = [...Length14, ...Length14];
type Length56 = [...Length28, ...Length28];
type VarRange = Exclude<keyof Length56, "0" | keyof any[]>
/* type VarRange = "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9" | "10" |
"11" | "12" | "13" | "14" | "15" | "16" | "17" | "18" | "19" | "20" | "21" |
"22" | "23" | "24" | "25" | "26" | "27" | "28" | "29" | ... 25 more ... | "55" */
interface VarInterface extends Record<`Var ${VarRange}`, string> { }

但我不知道这些对你来说是否值得。在某种程度上,维护硬编码的数字或字符串列表比维护复杂的类型操作代码更容易。

Playground链接到代码

最新更新