2016-10-24 97 views
1

我刚刚开始使用Typescript,并且我无法理解是否有可能将类属性作为对象,除了在类中声明的属性之外,该对象将包含任何任意属性。例如,我在此将name定义为Person的属性,然后在properties下,您应该能够为该人定义任何其他任意特征,例如其高度。看起来,分配它没问题,但试图访问它在第12行抛出一个错误说:具有任意属性作为类属性的对象

Property 'height' does not exist on type 'Object'

公平的够了!我知道不能保证一个名为height的属性可能只是一个对象,但仍然应该有办法做到这一点。

下面是代码:

class Person { 
    public name: string; 
    public properties: Object; 
    constructor(name: string, other: Object) { 
     this.name = name; 
     this.properties = other; 
    } 
} 

let props: Object = { height: 200 }; 
var nick = new Person("Bob", props); 
console.log(nick.properties.height); 

这里是我试过的替代,它抛出一模一样的错误:

class Person { 
    public name: string; 
    public properties: Object; 
    constructor(name: string, other:{ height: number }) { 
     this.name = name; 
     this.properties = other; 
    } 
} 


var nick = new Person("Bob", { height: 200 }); 
console.log(nick.properties.height); 

与接口另一种选择我只是试着,那仍然不起作用。

interface PersonProperties { 
    height: number; 
} 

class Person { 
    public name: string; 
    public properties: Object; 
    constructor(name: string, other: PersonProperties) { 
     this.name = name; 
     this.properties = other; 
    } 
    getHeight(): number { 
     return this.properties.height; 
    } 
} 

var properties: PersonProperties = { height: 200 }; 
var nick = new Person("Bob", properties); 
document.write(nick.getHeight().toString()); 
+0

你可以将其定义为任何类型 – Geeky

回答

5

由于静态类型的Person#properties简直是Object类型检查不保留任何关于它的其他类型的信息,这就是为什么你得到了编译错误。你能解决这个问题两种方式

“哑巴”的方式与any

class Person { 
    constructor(public name: string, public other: any) {} 
    /* ... */ 
} 

const p = new Person("doge", { wow : "such property" }) 
console.log(p.other.wow) // no error, also no type checking 

any在TS基本上是“禁用”的类型检查,并允许您访问类型为any

变量的任何属性

泛型

class Person<PropType> { 
    constructor(public name: string, public other: PropType) {} 
} 

const p = new Person("doge", { wow : "such property" }) 
console.log(p.other.wow) // ok 
console.log(p.other.amaze) // error 

这种方式稍微更聪明的方式每个人实例将有一个相关的p roperties类型,所以如果编译器知道您试图访问的属性,则会检查“编译”时间。

我建议你上仿制一些阅读,如果这看起来并不熟悉的其他语言版本:因为你定义public properties: Object;Object真的没有属性height发生https://www.typescriptlang.org/docs/handbook/generics.html

1

错误。即使您在构造函数中使用{ height: number }属性properties声明了正确的类型,但预计仍然是Object

例如,你可以这样做:

type PropertiesObject = { height: number }; 

class Person { 
    public name: string; 
    public properties: PropertiesObject; 
    constructor(name: string, other: PropertiesObject) { 
     this.name = name; 
     this.properties = other; 
    } 
} 

let props = <PropertiesObject>{ height: 200 }; 
var nick = new Person("Bob", props); 
console.log(nick.properties.height); 

使用界面,你所做的是正确的为好。

See live demo

请注意,您可以随时使用好老方括号表示法。即使仅使用Object,也应该成功编译:

console.log(nick.properties['height']); 
0

您可以使用类型映射。创建一个包含所有键(套)和类应该映射你想与(UserIdentifier的)工作,比混合,在你的函数(在我的例子用户对象的构造函数)的参数属性的类型

type Wrap<T> = { 
    [P in keyof T]?: T[P] 
} 

type UserIdentifier = { 
    userId: string; 
} 

class User { 
    constructor(user: Wrap<any> & UserIdentifier) { 
     this.user = user; 
    } 
    user: Wrap<any> & UserIdentifier; 

    userId(): string { 
     return this.user.userId; 
    } 

} 

//then can be called as 
let u = new User({userId:"usr1", someOther:1, andOther:2, andSoOn:3}); 
//or just 
let u2 = new User({userId:"usr1"}); 
//however this will throw an error because required userId property is not present 
let u3 = new User({someOther:1});