【问题标题】:JavaScript to TypeScript: Intellisense and dynamic membersJavaScript 到 TypeScript:智能感知和动态成员
【发布时间】:2017-02-15 10:28:04
【问题描述】:

我有一个 JavaScript 对象,它动态地允许成员作为访问器属性绑定到对象的实例:

来源

function DynamicObject(obj) {
    for (var prop in obj) {
        Object.defineProperty(this, prop, {
            get: function () { return obj[prop]; },
            set: function (value) { obj[prop] = value; },
            enumerable: true,
            configurable: false
        });
    }
}

用法

var obj = new DynamicObject({
    name: "John Smith",
    email: "john.smith@test.net",
    id: 1
});

创建obj 时,构造函数参数的成员绑定到obj 作为访问器属性。这些出现在智能感知中

我想知道是否可以在 TypeScript 中对这种行为(包括智能感知)进行建模?

备注

当你在 TypeScript 中运行这段代码时,没有智能感知,因为一切都是 any,所以 TypeScript 并不真正知道发生了什么。

【问题讨论】:

  • 我很好奇你为什么要这样做而不是只使用基本的对象文字。只是为了configurable: false?您可以只使用Object.freezeObject.seal 来执行类似的任务...
  • @MikeMcCaughan 不,这里的优势实际上在于 get/set 功能,而不是可配置性。
  • 那么,您的“真实”代码对 get/set 做了一些更有趣的事情吗?太酷了。

标签: javascript typescript


【解决方案1】:

我想知道是否可以在 TypeScript 中对这种行为(包括智能感知)进行建模?

是的。

您可以将通用调用签名分配给DynamicObject。您需要将其声明为变量:

var DynamicObject: new <T>(obj: T) => T = function (obj)
{
    for (var prop in obj)
    {
        Object.defineProperty(this, prop, {
            get: function () { return obj[prop]; },
            set: function (value) { obj[prop] = value; },
            enumerable: true,
            configurable: false
        });
    }
} as any;

这样,IntelliSense 会将new DynamicObject 返回的值视为与传入的值具有相同的类型。相同的属性名称,相同的属性类型。您将获得完全的自动完成和类型安全。

Live demo on TypeScript Playground


如果你在第一行的那部分无法理解,这与编写以下内容相同:

// Declare type (only exists during compile-time)
var DynamicObject: new <T>(obj: T) => T;

// Assign value (during runtime)
DynamicObject = function (obj)
{
    ...
} as any;

【讨论】:

  • 有没有机会让 DynamicObject 与 TypeScript 的继承模型一起工作? (对不起,我知道这是一个很高的要求!)
  • 我不完全确定你在这里问什么,但你可以尝试使用&amp; 运算符来定义intersection types
  • 在您的示例中,您有一个 DynamicObject 的实现。是否有可能保留此实现,并有能力做... class SomeSortOfDerivedObject extends DynamicObject { ... } ...我可以这样做吗?
【解决方案2】:

你不能。这些是完全动态的属性,在运行时添加,所以你不可能在编译时知道它们是什么。我还认为您不这么早知道它们是什么;如果您有强制执行的限制条件,则应单独说明它们(下面的第一个示例)。

如果您的代码依赖于一组访问器,您应该将它们直接放在接口或合同中,因为您提前知道您期望它们并且应该宣传它。您可以使用可选属性(访问器定义较低)来简化:

interface HasSomeProps {
  foo: string;
  bar?: string;
}

class DoesTheProps implements HasSomeProps {
  set foo(value) { 
    // ...
  }
}

如果您有一堆一致(或半一致)的访问器,您可以在您的类型上定义一个索引器,例如:

interface AccessStrings {
  [key: string]: string;
}

这不允许您限制键。如果需要,您应该明确列出属性。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2012-09-27
    • 1970-01-01
    • 2022-07-04
    • 2017-10-26
    • 1970-01-01
    • 2015-08-27
    • 2015-08-27
    • 1970-01-01
    相关资源
    最近更新 更多