有没有办法为动态生成的类方法名称创建类型定义,并遵循像
{name}Ref
这样的命名格式?基本上,我想知道这样的事情是否可能:
export declare class BaseElement extends HTMLElement {
// ... other type definitions ...
[`${Lowercase<string>}Ref`](): HTMLElement | null {} // <-- is something like this possible?
}
背景:
我正在构建一个自定义元素基类,它将查找具有属性
:ref="name"
的子元素,并在基类上动态创建一个新方法,该方法将返回对定义属性的节点的引用,并遵循命名格式: {name}Ref
。
此时代码已完全正常运行,但我在正确定义其类型时遇到问题。
这是基类的删节版本:
class BaseElement extends HTMLElement {
constructor() {
super();
// ... other stuff ...
this.generateRef(attr);
}
generateRef(attr) {
const refName = `${attr.value}Ref`;
this[refName] = () => attr.ownerElement;
}
}
问题:
当我在打字稿文件中使用/使用它时,我收到一条错误,指出该方法在子类中不存在。
这是问题的“最小重现”。
import {BaseElement} from './BaseElement.js';
class Child extends BaseElement {
constructor() {
super();
this.someRef(); // Error: Property 'someRef' does not exist on type 'Child'.
}
}
我发现我可以使用
declare
关键字来解决这个问题,但是在扩展 BaseElement 的每个类上声明每个引用可能会有点冗长/烦人。
class Child extends BaseElement {
declare someRef: () => HTMLElement | null;
constructor() {
super();
this.someRef();
}
}
如果 BaseElement 类能够负责定义方法类型而不是子类,那就太好了,因此我们回到上面的问题,这样的事情可能吗?
export declare class BaseElement extends HTMLElement {
// ... other type definitions ...
[`${Lowercase<string>}Ref`](): HTMLElement | null {} // <-- is something like this possible?
}
BaseElement 类是在 JavaScript 文件中定义的,然后我在
.d.ts
文件中手写了我的类型,因此如果答案可以满足实际情况,我们将不胜感激。
我还发现this StackOverflow问题似乎有些相关,并讨论了定义遵循{dynamicString}Postfix
模式的方法名称类型的解决方案,但我真的很难将该问题的解决方案转化为我正在研究的内容。
,如下所示:
declare class BaseElement extends HTMLElement {
[x: `${Lowercase<string>}Ref`]: (() => HTMLElement | null) | undefined
}
这意味着
BaseElement
的任何属性,其键是小写字符串后跟
"Ref"
,要么是返回 HTMLElement | null
的无参数函数,要么是 undefined
。仅匹配 `${Lowercase<string>}Ref`
的字符串才会被赋予该类型:this.ABCRef // error
this.abcRef // okay
this.abcDef // error
仅识别
this.abcRef
,因为它的形式正确,而
this.ABCRef
失败,因为 ABC
不是小写,abcDef
失败,因为它不以 Ref
结尾。请注意,我在值类型中添加了 undefined
可能性,以提醒您在调用它之前检查是否存在某些随机方法:
class Something extends BaseElement {
foo() {
const r = this.abcdeRef?.();
// optional chaining ->^^
// const r: HTMLElement | null | undefined
}
}
当且仅当存在时,使用可选链接运算符 (
?.
)
来调用
this.abcdeRef
,并且结果 r
是 HTMLElement | null
或 undefined
。建议检查 null
和
undefined
,但如果您不希望被迫执行此类检查,则可以从索引签名值中删除 undefined
(并确保 --noUncheckedIndexedAccess
是禁用)。如果您这样做,如果遇到运行时错误,请不要感到惊讶。Playground 代码链接