JavaScript for TypeScript: Intellisense and Dynamic Elements

I have a JavaScript object that dynamically allows members to bind as access properties to object instances:

A source

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 }); } } 

Using

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

When obj is created, the constructor parameter members are bound to obj as access properties. They appear in intellisense

Intellisense for Dynamic Members

I would like to know if it is possible to model this behavior (including the presence of intellisense) in TypeScript?

Notes

When you run this code in TypeScript, there is no intellisense, because everything is any , so TypeScript really does not know what is happening.

+5
source share
2 answers

I would like to know if it is possible to model this behavior (including the presence of intellisense) in TypeScript?

Yes.

You can assign a general signature to the DynamicObject call. You need to declare it as a variable:

 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; 

This way, IntelliSense will handle the value returned from new DynamicObject as having the same type as the value passed to. The names of the same properties, the same types of properties. You will get full autocomplete and type of security.

TypeScript Live Demo Playground


If you have problems wrapping your head around this part in the first line, this is the same as writing the following:

 // Declare type (only exists during compile-time) var DynamicObject: new <T>(obj: T) => T; // Assign value (during runtime) DynamicObject = function (obj) { ... } as any; 
+1
source

You can not. These are fully dynamic properties added at runtime, so you may not know that they are at compile time. I also claim that you do not want to know that they are at an early stage; if you have enforcement restrictions, you should simply declare them yourself (first example below).

If your code depends on a set of accessories, you should place them directly in the interface or contract, because you know in advance that you expect them and should advertise it. You can use additional properties (with a child access element) to make this easier:

 interface HasSomeProps { foo: string; bar?: string; } class DoesTheProps implements HasSomeProps { set foo(value) { // ... } } 

If you have a group of sequential (or semi-consistent) accessories, you can define an indexer for your type, for example:

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

This does not allow you to restrict keys. If you want this, you must explicitly specify the properties.

+5
source

Source: https://habr.com/ru/post/1257811/


All Articles