Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Dynamic TypeScript Typing

Is there any way to have dynamic object properties in a TypeScript class, and add dynamic Typings in for TypeScript?

I have seen similar questions but none with a complete example like this -

interface IHasObjectName {
   objectName: string;
}

class example<A extends IHasObjectName, B  extends IHasObjectName> {

    constructor(a: A, b: B) {
        this[a.objectName] = function() { return a; };
        this[b.objectName] = function() { return b; }
    }
}

class Cat implements IHasObjectName {
    objectName: string = "";
}

class Dog implements IHasObjectName {
    objectName: string = "";
}

let cat = new Cat();
cat.objectName = "Cat";

let dog = new Dog();
dog.objectName = "Dog";

let test = new example<Cat,Dog>(cat, dog);

// ??? TYPESCRIPT DOESN'T KNOW ABOUT THESE DYNAMIC PROPERTIES
// HOW DO I MAKE THIS WORK?
let d = test.Dog();
let c = test.Cat();

// I know I could access like this 
// let d = test["Dog"](); 
// but I want to access like function and have it typed
like image 747
user210757 Avatar asked Jun 22 '26 06:06

user210757


1 Answers

You can use a factory function and intersection:

function factory<A extends IHasObjectName, B extends IHasObjectName, C>(a: A, b: B): example<A, B> & C {
    return new example<Cat, Dog>(a, b) as C;
}
var test = factory<Cat, Dog, { Dog(): Dog, Cat(): Cat }>(cat, dog);

var d = test.Dog(); // no error
var c = test.Cat(); // no error

(code in playground)


Edit

You can't "reflect" types because they don't exist in runtime, but you can use the constructor.name of the passed in instances, so you can simply do this:

class example<A, B> {
    constructor(a: A, b: B) {
        this[a.constructor.name] = function() { return a; };
        this[b.constructor.name] = function() { return b; }
    }
}

class Cat {}

class Dog {}

var cat = new Cat();
var dog = new Dog();


function factory<A, B, C>(a: A, b: B): example<A, B> & C {
    return new example<Cat, Dog>(a, b) as C;
}
var test = factory<Cat, Dog, { Dog(): Dog, Cat(): Cat }>(cat, dog);

var d = test.Dog();
var c = test.Cat();

(code in playground)

like image 143
Nitzan Tomer Avatar answered Jun 23 '26 19:06

Nitzan Tomer



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!