TypeScript中对象文字中的类型定义


343

在TypeScript类中,可以声明属性的类型,例如:

class className {
  property: string;
};

如何在对象文字中声明属性的类型?

我已经尝试了以下代码,但无法编译:

var obj = {
  property: string;
};

我收到以下错误:

名称“字符串”在当前范围中不存在

我是在做错什么还是错误?

Answers:


423

您已经很接近了,只需将替换=为即可:。您可以使用对象类型文字(请参阅规范第3.5.3节)或接口。使用对象类型文字与您所拥有的差不多:

var obj: { property: string; } = { property: "foo" };

但是您也可以使用界面

interface MyObjLayout {
    property: string;
}

var obj: MyObjLayout = { property: "foo" };

14
@Rick Love与演员运算符一起执行的DRY(不要重复自己)选项似乎更加整洁。只是发表评论,而不是
拒绝投票

我知道这已经回答了一段时间了,但是我是否误以为当类具有方法和属性时会出现问题?由于该类未初始化,我们仅分配属性,因此在该类上调用方法将导致null异常。基本上,我们创建的对象仅是“ acts”作为类,因为我们为其分配了类型,但实际上并非该类的实例。也就是说,我们需要使用“ new”关键字创建类。然后我们回到平方1,因为我们不能做类似new class(){prop:1}的事情;例如在TS中,就像在C#中一样。
DeuxAlpha

@DeuxAlpha这是分配给一个接口,不能有方法。我不认为您可以分配这样的课程。
Mog0

链接到规范将是不错的:)
ahong

@DeuxAlpha,这是在创建对象文字,而不是类对象。接口也可以具有方法。如果您的接口定义了一个方法,那么对象文字也必须定义它-它不会为null。对象文字必须满足接口定义的所有内容,否则类型系统将显示错误。
Rick Love

288

更新2019-05-15(作为替代的改进的代码模式)

经过多年的使用 const并从更多的功能代码中受益,我建议大多数情况下不要使用以下代码。(在构建对象时,将类型系统强制为特定类型而不是让其推断类型通常表明存在问题)。

相反,我建议const尽可能使用变量,然后将对象组成最后一步:

const id = GetId();
const hasStarted = true;
...
const hasFinished = false;
...
return {hasStarted, hasFinished, id};
  • 这将正确键入所有内容,而无需显式键入。
  • 无需重新输入字段名称。
  • 根据我的经验,这可以得出最干净的代码。
  • 这使编译器可以提供更多的状态验证(例如,如果您在多个位置返回,则编译器将确保始终返回相同类型的对象-鼓励您在每个位置声明整个返回值-给出一个清晰清晰的该值的意图)。

增加2020-02-26

如果您确实需要可以延迟初始化的类型:将其标记为可为空的联合类型(null或Type)。类型系统会阻止您在没有先确保其值的情况下使用它。

在中tsconfig.json,确保启用严格的空检查:

"strictNullChecks": true

然后使用此模式,并允许类型系统保护您免受意外的空/未定义访问:



const state = {
    instance: null as null | ApiService,
    // OR
    // instance: undefined as undefined | ApiService,

};

const useApi = () => {
    // If I try to use it here, the type system requires a safe way to access it

    // Simple lazy-initialization 
    const api = state?.instance ?? (state.instance = new ApiService());
    api.fun();

    // Also here are some ways to only access it if it has value:

    // The 'right' way: Typescript 3.7 required
    state.instance?.fun();

    // Or the old way: If you are stuck before Typescript 3.7
    state.instance && state.instance.fun();

    // Or the long winded way because the above just feels weird
    if (state.instance) { state.instance.fun(); }

    // Or the I came from C and can't check for nulls like they are booleans way
    if (state.instance != null) { state.instance.fun(); }

    // Or the I came from C and can't check for nulls like they are booleans 
    // AND I was told to always use triple === in javascript even with null checks way
    if (state.instance !== null && state.instance !== undefined) { state.instance.fun(); }
};

class ApiService {
    fun() {
        // Do something useful here
    }
}

在99%的情况下,请勿执行以下操作:

2016年2月10日更新-处理TSX(感谢@Josh)

使用asTSX运算符。

var obj = {
    property: null as string
};

一个更长的例子:

var call = {
    hasStarted: null as boolean,
    hasFinished: null as boolean,
    id: null as number,
};

原始答案

使用强制转换运算符可以使其简洁(通过将null强制转换为所需的类型)。

var obj = {
    property: <string> null
};

一个更长的例子:

var call = {
    hasStarted: <boolean> null,
    hasFinished: <boolean> null,
    id: <number> null,
};

这比有两部分要好得多(一个用于声明类型,第二个用于声明默认值):

var callVerbose: {
    hasStarted: boolean;
    hasFinished: boolean;
    id: number;
} = {
    hasStarted: null,
    hasFinished: null,
    id: null,
};

10
如果使用的是TSX(带有JSX的TS),则不能使用尖括号命名,因此这些行将变成类似这样的地方,property: null as string其中重要的区别在于as运算符。
乔什

2
@RickLove这是否实际上限制了对象变量的类型,或者这只是分配时指定类型的一种方式?换句话说,在call第二个示例中分配了变量之后,是否可以为其分配完全不同的类型?
丹尼尔·格里斯康

3
这应该是答案
Drew R

4
不工作。Error:(33, 15) TS2352:Type 'null' cannot be converted to type 'string'.
slideshowp2

2
这仅仅是对语言功能的滥用还是实际上是合法的?您能否提供正式阅读文档的阅读链接?谢谢!
Qwerty

31

我很惊讶没有人提到这一点,但是您可以创建一个名为的接口ObjectLiteral,该接口接受key: value成对的type string: any

interface ObjectLiteral {
  [key: string]: any;
}

然后,您将使用它,如下所示:

let data: ObjectLiteral = {
  hello: "world",
  goodbye: 1,
  // ...
};

另外一个好处是,您可以根据需要在任意数量的对象上多次重复使用此接口。

祝好运。


3
这是一个坏主意,它使类型系统毫无价值。打字稿的重点是允许打字稿系统防止错误,并在工具中提供更好的自动完成功能-这基本上使打字稿的所有优点无效。最好不要在上面的示例中使用任何接口。
里克·洛夫

1
@RickLove我非常不同意。当几个属性是可选的,但我们仍然想清楚地定义其中的所有类型时(例如,包含函数的参数),此功能特别有用。可以简单地将其视为语法糖,并且实际上可以像Interfaces属性传播算子一样工作。
CPHPython

@CPHPython为什么不只使用其特定类型指定可选参数?只有在代码时不知道名称(即它们来自数据库或外部源)的情况下,这才有意义。同样对于复杂的参数组合,联合类型也很有效。如果要针对特定​​名称进行编码,则应尽可能定义它们。如果只是数据不影响逻辑,那么当然将其排除在类型系统之外。
里克·洛夫

1
@RickLove“名称在代码时不知道”->这是一个很好的实际示例,这些键类型的值是已知的,并且它们都是相同的(例如string)。请记住,我只是在提倡使用[key: string]部分,而不是将任何部分用作值的类型定义...那确实会消除类型的用途。
CPHPython

1
如果要允许添加字符串和数字而不允许其他类型,该怎么办?
DonkeyBanana

14

如果您尝试编写类型注释,则语法为:

var x: { property: string; } = ...;

如果您尝试编写对象文字,则语法为:

var x = { property: 'hello' };

您的代码试图在值位置使用类型名称。


10
var x: { property: string; } = ...;是个逗人!我希望省略号是有效的简化语法var x: { property: string; } = { property: 'hello' };
詹森·克莱本

10

在TypeScript中,如果我们声明对象,则将使用以下语法:

[access modifier] variable name : { /* structure of object */ }

例如:

private Object:{ Key1: string, Key2: number }

7

如果您尝试向解构的对象常量添加类型,例如在函数的参数中,则语法为:

function foo({ bar, baz }: { bar: boolean, baz: string }) {
  // ...
}

foo({ bar: true, baz: 'lorem ipsum' });

5

如果您的属性具有相同的类型,则可以使用预定义的实用程序类型Record

type Keys = "property" | "property2"

var obj: Record<Keys, string> = {
  property: "my first prop",
  property2: "my second prop",
};

当然,您可以进一步定义属性值的自定义类型:

type Keys = "property" | "property2"
type Value = "my prop" | "my other allowed prop"

var obj: Record<Keys, Value> = {
  property: "my prop",
  property2: "my second prop", // TS Error: Type '"my second prop"' is not assignable to type 'Value'.
};

2
正是我所需要的。谢谢!打字稿赢了!
Audacitus

我也用let代替var这里。
Fwd079

3
// Use ..

const Per = {
  name: 'HAMZA',
  age: 20,
  coords: {
    tele: '09',
    lan: '190'
  },
  setAge(age: Number): void {
    this.age = age;
  },
  getAge(): Number {
    return age;
  }
};
const { age, name }: { age: Number; name: String } = Per;
const {
  coords: { tele, lan }
}: { coords: { tele: String; lan: String } } = Per;

console.log(Per.getAge());

3
嘿,欢迎来到!您能否扩展您的答案,这将有助于解释其工作原理/原因。
派对

1

在您的代码中:

var obj = {
  myProp: string;
};

您实际上是在创建对象文字并将变量字符串分配给属性myProp。尽管这是非常糟糕的做法,但实际上这将是有效的TS代码(请勿使用此代码!):

var string = 'A string';

var obj = {
  property: string
};

但是,您想要的是键入对象文字。这可以通过多种方式实现:

接口:

interface myObj {
    property: string;
}

var obj: myObj = { property: "My string" };

自定义类型:

type myObjType = {
    property: string
};

var obj: myObjType = { property: "My string" };

演员:

var obj = {
    myString: <string> 'hi',
    myNumber: <number> 132,
};

对象类型文字:

var obj: { property: string; } = { property: "Mystring" };
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.