如何解决TypeScript中动态,无限,编号变量名称的类型定义
我正在为没有类型定义的jQuery库编写类型定义文件(index.d.ts
)。
某些方法需要一个对象作为参数,该对象具有所有可用属性集的子集。除了显式定义的变量外,该库还提供了使用无限数量的编号变量的功能(本质上是一个数组的实现,没有实际数组的好处)。
export interface SomeLibOption {
a?: number,b?: string,c?: boolean,// so far so good,Now the problematic part:
x?: number,x2?: number,x3?: number,x4?: number,x5?: number,// ...
x1000?: number,// ...
x500000?: number,// ...
}
declare global {
interface JQuery<TElement = HTMLElement> {
setFoo(foo: SomeLibOption): this;
setBar(bar: SomeLibOption): this;
}
}
用法如下:
$('someSelector').setBar({
a: 2,x: 3,x1: 9,x2: 5,x3: 4,// ...
x1000: 42,// ...
});
对所有可能的变量名进行硬编码似乎是不可行的。毕竟它们是无限的。
如何在类型定义文件中定义它们?甚至有可能吗?
澄清
我正在寻找一种解决方案,将'x' + number
定义为有效属性,但将'y' + number
定义为有效属性,同时保留诸如a?: number,c?: boolean
之类的现有定义。
基本上,属性应与正则表达式/^x[0-9]+$/
相匹配。
解决方法
TypeScript 4.1将像Column name Data type Constraints
DEPARTMENT_ID NUMBER(5) PK
DEPARTMENT_NAME VARCHAR2(25) NOT NULL
LOCATION_ID VARCHAR2(15)
Sample Output:
Department Details are :
1000,ADMIN,HQ-101
1010,DEVELOPMENT,CBE-103
1020,TESTING,CHN-102
一样支持template literal types来表示字符串连接。它还将支持recursive conditional types。
您将无法将set serveroutput on;
declare
v_dno department.department_id%type;
v_dname department.department_name%type;
v_loc department.location_id%type;
begin
dbms_output.put_line('Department Details are :');
loop
dbms_output.put_line(v_dno || ',' || v_dname || ',' || v_loc);
end loop;
commit;
end;
/
形式的无限属性表示为TypeScript中的具体类型,至少据我所知。根据{{3}}的规定,对模板文字类型(如`${A}${B}`
的支持如下:
"x"+number
,但是它并没有按照您在此处需要的方式扩展到键类型:
`x${number}`
否则,您将只能将type XNumber = `x${"" | number}`;
let xNumber: XNumber;
xNumber = "x12345"; // okay
xNumber = "xNope"; // error!
xNumber = "y"; // error!
xNumber = "x-3.14159"; // okay I guess
表示为microsoft/TypeScript#40598而不是特定类型。
模板字面量操作目前很棘手,因为存在两个主要陷阱:联合类型爆炸和递归限制。从概念上讲,您可以提出一种const foo: Partial<Record<XNumber,number>> = {};
foo.x = 1;
foo.x12345 = 2; // error! ?
之类的SomeLibOption
类型,然后说您将接受Digit
类型的键,然后是0|1|2|3|4|5|6|7|8|9
。但这是一个巨大的结合,它破坏了编译器。因此,相反,您可以将其表示为诸如"x"
之类的递归类型检查,但由于递归限制,该类型最终会在长字符串如`${Digit}${Digit}${Digit}${Digit}${Digit}${Digit}`
上轰炸。
以下示例尝试通过使用type IsDigits<T extends string> = T extends "" ? "yes" : `${Digit}${infer U}` ? IsDigits<U> : "no"
进行100个元素的适度合并,并对两个数字或一个数字的组进行递归来在它们之间走线:
IsDigits<"13263548274827">
一团糟,但这是您的${Digit}${Digit}
方法:
interface BaseLibOption {
a?: number,b?: string,c?: boolean,}
type Digit = 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9;
type IsAllDigits<T extends string,Y = T,N = never> = string extends T ? N :
T extends "" ? Y : T extends `${Digit}${Digit}${infer U}` ? IsAllDigits<U,Y,N> :
T extends `${Digit}${infer U}` ? IsAllDigits<U,N> : N
type SomeLibOption<T> = { [K in keyof T]?: K extends keyof BaseLibOption ? BaseLibOption[K] :
K extends `x${infer N}` ? IsAllDigits<N,number> : never }
让我们看看它是否有效:
JQuery
我认为不错。
,使用此符号,您可以定义一个接口,该接口将具有任意数量的属性,其键始终为字符串,值始终为数字
interface MyInterface {
[key: string]: number
}
下面是一个使用与您的问题相同的接口名称的示例,并简单演示了如何在函数定义和调用中使用它。
// Define an interface with an arbitrary of key value pairs in which
// keys are always strings and values are always numbers
interface SomeLibOption {
[key: string]: number
}
// Example function with a parameter of type
// SomeLibOption defined above
function setBar(op: SomeLibOption) {
// Do something...
// For example,the following line prints out sum of op.a and op.b
console.log(`a + b = ${op.a + op.b}`)
}
// Example function call passing in a SomeLibOption
// object that has arbitrary key value pairs
setBar({
a: 1,b: 2,c: 3,a2: 400,b2: 500
})
请注意,每个语句后的分号
;
都被省略了,因为我们假设我们使用的是TypeScript版本。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。