如何为具有相似名称的变量列表创建打字稿接口?
How can I create a typescript interface for a list of variables with similar names?
我想声明一个接口,其中包含许多名称相似的变量,但我不想手动创建它。类型就像
interface {
"Var 1": string;
"Var 2": string;
"Var 3": string;
"Var 4": string;
"Var 5": string;
}
这个列表最多可以有 55 个,所以在界面中写下所有的变量名是不可行的。
您可以将 template literal types to turn a union 的数字类型用于您正在查找的键中。假设您有一个名为 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 中,它们将 lift some recursion restrictions 语言,你将能够这样做:
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> { }
它使用recursive conditional types and variadic tuple types构建一个长度为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> { }
但我不知道这些对你来说是否值得。在某些时候,维护数字或字符串的硬编码列表比维护复杂类型操作代码更容易。
我想声明一个接口,其中包含许多名称相似的变量,但我不想手动创建它。类型就像
interface {
"Var 1": string;
"Var 2": string;
"Var 3": string;
"Var 4": string;
"Var 5": string;
}
这个列表最多可以有 55 个,所以在界面中写下所有的变量名是不可行的。
您可以将 template literal types to turn a union 的数字类型用于您正在查找的键中。假设您有一个名为 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 中,它们将 lift some recursion restrictions 语言,你将能够这样做:
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> { }
它使用recursive conditional types and variadic tuple types构建一个长度为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> { }
但我不知道这些对你来说是否值得。在某些时候,维护数字或字符串的硬编码列表比维护复杂类型操作代码更容易。