Typescript 具有任意属性作为类属性的对象

Typescript 具有任意属性作为类属性的对象,typescript,Typescript,我只是从Typescript开始,我不明白是否有可能将一个类属性设置为一个对象,该对象除了在类中声明的属性外,还包含任何任意属性。例如,我在这里将姓名定义为人的属性,然后在属性下,您应该能够定义该人的任何其他任意特征,例如身高。似乎分配它是正常的,但尝试在第12行访问它会抛出一个错误,即: 类型“Object”上不存在属性“height” 很公平!我知道不能保证名为height的属性会位于只是一个对象的对象下,但应该有办法做到这一点 代码如下: class Person { public

我只是从Typescript开始,我不明白是否有可能将一个类属性设置为一个对象,该对象除了在类中声明的属性外,还包含任何任意属性。例如,我在这里将
姓名
定义为
人的属性
,然后在
属性
下,您应该能够定义该人的任何其他任意特征,例如身高。似乎分配它是正常的,但尝试在第12行访问它会抛出一个错误,即:

类型“Object”上不存在属性“height”

很公平!我知道不能保证名为
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());

由于
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
ts中的
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
班级人员{
构造函数(公共名称:string,公共其他:PropType){}
}
const p=新人(“doge”,{wow:“这样的财产”})
console.log(p.other.wow)//好的
console.log(p.other.amaze)//错误
这样,每个person实例都将有一个关联的属性类型,因此,如果编译器知道您试图访问的属性,则会在“编译”时检查它


如果泛型在其他语言中看起来不熟悉,我建议您阅读一些泛型:

因为
Person\35; 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
ts中的
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
班级人员{
构造函数(公共名称:string,公共其他:PropType){}
}
const p=新人(“doge”,{wow:“这样的财产”})
console.log(p.other.wow)//好的
console.log(p.other.amaze)//错误
这样,每个person实例都将有一个关联的属性类型,因此,如果编译器知道您试图访问的属性,则会在“编译”时检查它


如果泛型在其他语言中看起来不太熟悉,我建议您阅读一些泛型:

发生错误的原因是您正在定义
公共属性:Object
对象
实际上没有属性
高度
。即使您使用
{height:number}
属性
属性
在构造函数中声明了正确的类型,但仍然希望它是
对象

例如,您可以这样做:

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

发生错误的原因是您正在定义
公共属性:对象
对象
实际上没有属性
高度
。即使您使用
{height:number}
属性
属性
在构造函数中声明了正确的类型,但仍然希望它是
对象

例如,您可以这样做:

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

您可以使用类型映射。创建由所有键(Wrap)和类组成的类型,这些键和类应该映射您想要使用的属性(UserIdentifier),然后在函数的参数(在我的示例中是User对象的构造函数)中混合这些属性

类型换行={
[P在keyof T]?:T[P]
}
类型UserIdentifier={
userId:string;
}
类用户{
构造函数(用户:Wrap和UserIdentifier){
this.user=用户;
}
用户:Wrap&UserIdentifier;
userId():字符串{
返回this.user.userId;
}
}
//那么可以称为
设u=newuser({userId:“usr1”,someOther:1,andOther:2,andSoOn:3});
//或者只是
设u2=新用户({userId:“usr1”});
//但是,这将引发错误,因为所需的userId属性不存在
设u3=新用户({someOther:1});

您可以使用类型映射。创建由所有键(Wrap)和类组成的类型,这些键和类应该映射您想要使用的属性(UserIdentifier),然后在函数的参数(在我的示例中是User对象的构造函数)中混合这些属性

类型换行={
[P在keyof T]?:T[P]
}
类型UserIdentifier={
userId:string;
}
类用户{
构造函数(用户:Wrap和UserIdentifier){
this.user=用户;
}
用户:Wrap&UserIdentifier;
userId():字符串{
返回this.user.userId;
}
}
//那么可以称为
设u=newuser({userId:“usr1”,someOther:1,andOther:2,andSoOn:3});
//或者只是
设u2=新用户({userId:“usr1”});
//但是,这将引发错误,因为所需的userId属性不存在
设u3=新用户({someOther:1});

您可以将其定义为任何类型您可以将其定义为任何类型