简体   繁体   English

动态TypeScript键入

[英]Dynamic TypeScript Typing

Is there any way to have dynamic object properties in a TypeScript class, and add dynamic Typings in for TypeScript? 有没有办法在TypeScript类中拥有动态对象属性,并为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

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: 您不能“反映”类型,因为它们在运行时不存在,但您可以使用传入实例的constructor.name ,因此您可以简单地执行此操作:

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 ) 游乐场代码

You need to cast it to any object type if you wan't "JavaScript behavior" in TypeScript. 如果您在TypeScript中不是“JavaScript行为”,则需要将其强制转换为any对象类型。

There are two syntax types, which are equivalent: 有两种语法类型,它们是等价的:

const d = (<any>test).Dog();
const c = (<any>test).Cat();

and

const testAny = test as any;
const d = testAny.Dog();
const c = testAny.Cat();

the last one was created for support in tsx files, where wouldn't work and is now the recommended way. 最后一个是为tsx文件中的支持而创建的,哪里不起作用,现在是推荐的方式。

There is hardly an other way to do that other than use the indexer, since the properties are dynamic and not typed. 除了使用索引器之外,几乎没有其他方法可以做到这一点,因为属性是动态的而不是键入的。

BTW I encourage to use const and let instead of var . BTW我鼓励使用constlet ,而不是var

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM