是否可以在打字稿中为动态生成的类方法创建类型定义?

问题描述 投票:0回答:1

有没有办法为动态生成的类方法名称创建类型定义,并遵循像

{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模式的方法名称类型的解决方案,但我真的很难将该问题的解决方案转化为我正在研究的内容。

    

javascript typescript types web-component custom-element
1个回答
0
投票
模板字符串模式索引签名

,如下所示: 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 代码链接

© www.soinside.com 2019 - 2024. All rights reserved.