Typescript 命名空间——字段的动态定义(JS 到 TS)
TypesScript namespace - dynamic definition of fields (JS to TS)
我正在尝试在不破坏 public API.
的情况下将此 JavaScript 代码从 atom/etch 转换为 TypeScript
它同时定义了一个dom-function
和一个dom-array of functions
(两者具有相同的名称dom
):
// called by the following loop
function dom (tag, props, ...children) {
// ...
}
const HTML_TAGS = [
'a', 'abbr'] // ... has more elements though
// similarly SVG-Tags is defined
// finds the array of functions
for (const tagName of HTML_TAGS) {
dom[tagName] = (props, ...children) => {
return dom(tagName, props, ...children)
}
}
for (const tagName of SVG_TAGS) {
dom[tagName] = (props, ...children) => {
return dom(tagName, props, ...children)
}
}
module.exports = dom
这个的等效 TypeScript 版本是什么?
其他包使用 dom 如 dom.a(tag, props, childern)
an example, or using @jsx etch.dom
an example
通过 运行 dts-gen
,我得到一个名为 dom
的命名空间,其中包含在 for 循环中定义的所有函数。
export namespace dom {
function a(props: any, children: any): any;
function abbr(props: any, children: any): any;
//...
}
这里是my branch.
我假设您正在为 dom.js
.
创建一个 dom.d.ts
类型定义文件
名称空间不是 dom
的正确类型。运行时 JS 中的 TS 命名空间呈现为普通对象。但是 dom
既是一个可调用函数,也是一个具有额外属性的对象。因此,您应该使用具有可调用签名的接口来表示 TS 中的 dom
。
dom.d.ts
interface EtchElement<T extends string, P = any> {
tag: T;
props: P;
children: any[];
ambiguous: any[];
}
type EtchCreateElement<T extends string, P> = (props: P, ...children: any[]) => EtchElement<T, P>;
interface EtchDOM {
<T extends string, P>(tag: T, props: P, ...children: any[]): EtchElement<T, P>;
div: EtchCreateElement<"div", any>;
// ... more tags here
}
declare const dom: EtchDOM;
export = dom;
JSX 支持
现在,如果您还打算支持 JSX 使用,则需要先通读官方 JSX guide 以了解相关要求。我将突出显示此摘录:
Intrinsic elements are looked up on the special interface JSX.IntrinsicElements. [...] if this interface is present, then the name of the intrinsic element is looked up as a property on the JSX.IntrinsicElements interface.
综上所述,这是一个有效的适度类型定义:
interface EtchElement<T extends string, P = any> {
tag: T;
props: P;
children: any[];
ambiguous: any[];
}
type EtchCreateElement<T extends string, P> = (props: P, ...children: any[]) => EtchElement<T, P>;
interface EtchDOM {
<T extends string, P>(tag: T, props: P, ...children: any[]): EtchElement<T, P>;
div: EtchCreateElement<"div", JSX.IntrinsicElements["div"]>;
// ... more tags here
}
declare const dom: EtchDOM;
export = dom;
declare global {
namespace JSX {
interface Element extends EtchElement<any, any> {}
interface IntrinsicElements {
div: any; // constraint on props of "div" element
}
}
}
我正在尝试在不破坏 public API.
的情况下将此 JavaScript 代码从 atom/etch 转换为 TypeScript它同时定义了一个dom-function
和一个dom-array of functions
(两者具有相同的名称dom
):
// called by the following loop
function dom (tag, props, ...children) {
// ...
}
const HTML_TAGS = [
'a', 'abbr'] // ... has more elements though
// similarly SVG-Tags is defined
// finds the array of functions
for (const tagName of HTML_TAGS) {
dom[tagName] = (props, ...children) => {
return dom(tagName, props, ...children)
}
}
for (const tagName of SVG_TAGS) {
dom[tagName] = (props, ...children) => {
return dom(tagName, props, ...children)
}
}
module.exports = dom
这个的等效 TypeScript 版本是什么?
其他包使用 dom 如 dom.a(tag, props, childern)
an example, or using @jsx etch.dom
an example
通过 运行 dts-gen
,我得到一个名为 dom
的命名空间,其中包含在 for 循环中定义的所有函数。
export namespace dom {
function a(props: any, children: any): any;
function abbr(props: any, children: any): any;
//...
}
这里是my branch.
我假设您正在为 dom.js
.
dom.d.ts
类型定义文件
名称空间不是 dom
的正确类型。运行时 JS 中的 TS 命名空间呈现为普通对象。但是 dom
既是一个可调用函数,也是一个具有额外属性的对象。因此,您应该使用具有可调用签名的接口来表示 TS 中的 dom
。
dom.d.ts
interface EtchElement<T extends string, P = any> {
tag: T;
props: P;
children: any[];
ambiguous: any[];
}
type EtchCreateElement<T extends string, P> = (props: P, ...children: any[]) => EtchElement<T, P>;
interface EtchDOM {
<T extends string, P>(tag: T, props: P, ...children: any[]): EtchElement<T, P>;
div: EtchCreateElement<"div", any>;
// ... more tags here
}
declare const dom: EtchDOM;
export = dom;
JSX 支持
现在,如果您还打算支持 JSX 使用,则需要先通读官方 JSX guide 以了解相关要求。我将突出显示此摘录:
Intrinsic elements are looked up on the special interface JSX.IntrinsicElements. [...] if this interface is present, then the name of the intrinsic element is looked up as a property on the JSX.IntrinsicElements interface.
综上所述,这是一个有效的适度类型定义:
interface EtchElement<T extends string, P = any> {
tag: T;
props: P;
children: any[];
ambiguous: any[];
}
type EtchCreateElement<T extends string, P> = (props: P, ...children: any[]) => EtchElement<T, P>;
interface EtchDOM {
<T extends string, P>(tag: T, props: P, ...children: any[]): EtchElement<T, P>;
div: EtchCreateElement<"div", JSX.IntrinsicElements["div"]>;
// ... more tags here
}
declare const dom: EtchDOM;
export = dom;
declare global {
namespace JSX {
interface Element extends EtchElement<any, any> {}
interface IntrinsicElements {
div: any; // constraint on props of "div" element
}
}
}