如何在TypeScript中初始化一个对象

123

我有一个简单的模型类

export interface Category {

  name: string;
  description: string;

}

我需要在 Angular 组件中声明并初始化一个变量。尝试过:

category: Category = {};

错误: {} 无法分配到一个类别

category: Category = new Category();

错误:类别指的是一种类型,但被指定为值。

有什么建议吗?

12个回答

216

解决这个问题有多种方法,具体取决于您的期望结果。

方法1:将您的interface转换为一个class

export class Category {
  name: string;
  description: string;
}
const category: Category = new Category();

方法二:将您的接口扩展为

export class CategoryObject implements Category {
}
const category: Category = new CategoryObject();

第三种方式:完全指定您的对象,与 interface 匹配

const category: Category = {
  name: 'My Category',
  description: 'My Description',
};

第四种方法:将属性设置为可选

export interface Category {
  name?: string;
  description?: string;
}

const category: Category = {};

第五种方法:将您的变量类型更改为使用Partial<T>

export interface Category {
  name: string;
  description: string;
}

const category: Partial<Category> = {};

1
我们稍后会分配正确的属性,只是不作为初始化的一部分,做一些额外的事情(你建议的5件事之一)只是为了实现这个看起来有点过度。 - gaurav5430
1
@gaurav5430 我提供的所有选项都能够为开发者和IDE提供准确的数据形状描述。如果您没有分配所有属性,则源代码中存在一些未分配属性的段落,此时应用部分类型定义。如果您只是想绕过TypeScript类型检查(为什么不使用JavaScript而选择TypeScript?),您可以将其分配为:const category: Category = {} as any。我不建议这样做,也不会将其添加到我的答案中。 - Ian MacDonald
“源代码的某些部分没有被分配属性”,如果在分配所有属性之前尝试使用该对象,那么这肯定会成为一个问题。但是,如果属性在下一行被分配,我希望 TypeScript 不会抱怨。再次强调,我谈论的是期望,我理解 TypeScript 可能无法按设计实现这一点。 - gaurav5430
2
我认为更简单的解决方案就是 let category = <Category>{ }; (仅当您确信要添加所有属性时)。 - RamoFX
在后续使用 API 响应数据填充对象时,使用 Partial 初始化对象是否正确?例如:const data: Partial<DataType> = {}; - Caio Mar
我刚意识到这个也可以:const data = <DataType>{}; -- 两种方式都正确吗? - Caio Mar

54

如果你不想把你的定义从interface改为class,你也可以这样做:

let category = <Category>{ };
否则,您可以按照其他答案的建议,将您的 Category 更改为类。 编辑: 根据下面ruffin的评论,如果界面是
export interface ITiered { one: { two: { three: function (x) {...} } } } 

如果您尝试let x = {} as ITiered,然后调用像x.one.two.three()这样的内容时,将会出现错误。


1
如果接口不像此示例中的单层可空接口,那么这不是很危险吗?即,如果接口为 export interface ITiered { one: { two: { three: function (x) {...} } } } 并且您尝试 let x = {} as ITiered,那么 x.one.two.three() 不会在没有定义 two 的情况下崩溃吗?我想我应该设置一个最简单的情况... ;^) - ruffin
2
是的,那个会出错。main.ts:11 错误 类型错误:无法读取未定义的属性“two” 你已经被警告了。 ;^D - ruffin
1
好的,我会在我的回答中加上那个免责声明。 :) - Vitor M. Barbosa
1
太棒了!为什么这不是最受欢迎的答案?... - RamoFX
你能解释一下这个语法的含义吗?我认为 <GenericType> 意味着一个泛型类型。但是仅仅指一个泛型类型,具体意思是什么? - Jimmy Chu
在JSX文件中使用<Category>{}语法是否可行? - friederbluemle

24

在Typescript中,如果你想使用对象初始化器,你需要在类中定义所有属性。

let category: Category = {
    name: '',
    description: ''
};

这种方法可以使您的模型仍保持为接口。


24
export interface Category {
  name: string;
  description: string;
}


category = {} as Category ;

编辑:想把下面的评论放在答案中,这样人们就知道我的答案为什么是错误的。我假设你总是会立即分配,但这不是一个好的假设。

现在你的系统中有一个被认为是某种类型,但缺少一些必要属性的对象。这只会导致在某个地方出错,是错误的建议。


2
现在您的系统中有一个对象,假定它属于某种类型,但缺少一些必要的属性。这只会导致错误,在某个地方出现问题。 - chpio

7

类似于 C# 的类:

export class Category {
    category: number = null;
    description: string = null;
    name: string = null;

  public constructor(init?: Partial<Category>) {
        Object.assign(this, init);
}
}

现在,当您创建一个新实例时,所有字段名称都是可用的并且为空。
 const instance_of_category: Category = new Category();

现在您拥有一个空的类对象,其中所有字段都已定义,就像C#一样:

instance_of_category{
    "category": null,
    "description": null,
    "name": null
}

6

您的对象字面量必须与接口匹配。由于您的接口有两个必需属性(namedescription),因此在实例化对象时必须同时声明它们。

const category: Category = {
    name: 'foo',
    description: 'bar'
};

如果你不能一开始就构建整个对象,你可以使用内置的 Partial 类型来构建对象。

const builder: Partial<Category> = {};
builder.name = 'foo';
builder.description = 'bar';

const category: Category = builder as Category;

2
如果您已经有一个类,并且想要同时创建新实例并初始化属性,可以尝试以下方法:
return Object.assign(new Person(), {
    name:"Your Name"
});

1
interface Person{
    id: number; 
    name: string;
}

let x: Person = {
    id : 0,
    name :"JOHN"
};

alert(x.name);

0
let category = <Category>{ };

当您不想更改接口或类的定义时,可以采用这种方式。

通过这种方式,将创建一个通用对象类型,它不依赖于数据类型,并且可重复使用。


0

您也可以使用Record类型。

{
    category: Record<string, string>;
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接