2016-10-24 2 views
1

Я только начинаю с Typcript, и я не могу понять, возможно ли иметь свойство класса как объект, который будет содержать любое произвольное свойство в дополнение к свойствам, объявленным в классе. Например, я определил здесь name как свойство Person, а затем под properties вы должны иметь возможность определять любые другие произвольные характеристики для человека, такие как их высота. Кажется, что назначение это идет нормально, но при попытке открыть его в строке 12 выдает ошибку, говоря:Объект с произвольными свойствами как свойство класса

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

достаточно Fair! Я знаю, что нет гарантии, что свойство с именем 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 типа проверка не хранит никакой дополнительной информации о типе об этом, поэтому вы получаете ошибки компиляции. Вы можете решить эту проблему 2 способа

«немой» путь с 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 в тс в основном «отключает» проверки типов, а также позволяет получить доступ к любому свойства на переменной, введенной как 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 

Таким образом, каждый экземпляр человек будет иметь соответствующий р тип roperties, поэтому он проверяет время «компиляции», если свойство, к которому вы пытаетесь получить доступ, известно компилятору.

я бы рекомендовал почитать на дженерики, если это не выглядит знакомым из других языков: https://www.typescriptlang.org/docs/handbook/generics.html

1

ошибка происходит потому, что вы определяете public properties: Object; и Object действительно не имеют свойство height. Даже если вы укажете правильный тип в конструкторе с { 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

Вы можете использовать отображение типов. Создание типа, который состоит из всех ключей (Wrap) и класс, который должен отображающих свойства, которые вы хотите работать (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}); 
Смежные вопросы