在TypeScript中的对象文字中键入定义

Dac*_*ina 286 typescript

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

class className {
  property: string;
};
Run Code Online (Sandbox Code Playgroud)

我应该如何编写代码来声明对象文字中属性的类型?这样的代码不编译:

var obj = {
  property: string;
};
Run Code Online (Sandbox Code Playgroud)

(我收到错误 - 当前范围中不存在名称'string').

我做错了什么或者是一个错误?

小智 367

你很近,你只需要替换=一个:.您可以使用对象类型文字(请参阅规范第3.5.3节)或界面.使用对象类型文字与您拥有的文字很接近:

var obj: { property: string; } = { property: "foo" };
Run Code Online (Sandbox Code Playgroud)

但您也可以使用界面

interface MyObjLayout {
    property: string;
}

var obj: MyObjLayout = { property: "foo" };
Run Code Online (Sandbox Code Playgroud)

  • @Rick Love与演员的DRY(不要重复自己)选项似乎更加整洁.只是评论,而不是低估... (9认同)

Ric*_*ove 256

使用强制转换操作符来简化(通过将null转换为所需的类型).

var obj = {
    property: <string> null
};
Run Code Online (Sandbox Code Playgroud)

更长的例子:

var call = {
    hasStarted: <boolean> null,
    hasFinished: <boolean> null,
    id: <number> null,
};
Run Code Online (Sandbox Code Playgroud)

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

var callVerbose: {
    hasStarted: boolean;
    hasFinished: boolean;
    id: number;
} = {
    hasStarted: null,
    hasFinished: null,
    id: null,
};
Run Code Online (Sandbox Code Playgroud)

更新2016-02-10 - 处理TSX(谢谢@Josh)

使用TSX的as运算符.

var obj = {
    property: null as string
};
Run Code Online (Sandbox Code Playgroud)

更长的例子:

var call = {
    hasStarted: null as boolean,
    hasFinished: null as boolean,
    id: null as number,
};
Run Code Online (Sandbox Code Playgroud)

  • 如果您使用的是TSX(带有JSX的TS),则不能使用尖括号命名,因此这些行变为类似`property:null as string`,其中重要的区别是`as`运算符. (8认同)
  • 不工作 `错误:(33,15)TS2352:类型'null'不能转换为'string'类型 (4认同)
  • 这应该是答案 (3认同)
  • @RickLove这实际上是否约束了对象变量的类型,或者这只是一种在分配时指定类型的方法?换句话说,在第二个例子中指定变量`call`之后,你能为它分配一个完全不同的类型吗? (2认同)
  • 这只是对语言功能的滥用还是这实际上是合法的?你能提供阅读官方文档的链接吗?谢谢! (2认同)
  • @LidelnKyoku IIFE 模式已过时。它已被模块和块作用域等所取代。您应该阅读 ECMAscript 模块。这是一篇可能有帮助的博客文章:https://tylermcginnis.com/javascript-modules-iifes-commonjs-esmodules/ (2认同)
  • @RickLove 你为什么说:**在 99% 的情况下不要执行以下操作**? (2认同)

str*_*tss 29

您可以使用预定义的实用程序类型Record<Keys, Type>

const obj: Record<string, string> = {
  property: "value",
};
Run Code Online (Sandbox Code Playgroud)

它允许为您的对象文字指定键:

type Keys = "prop1" | "prop2"

const obj: Record<Keys, string> = {
  prop1: "Hello",
  prop2: "Aloha",
  something: "anything" // TS Error: Type '{ prop1: string; prop2: string; something: string; }' is not assignable to type 'Record<Keys, string>'.
                        //   Object literal may only specify known properties, and 'something' does not exist in type 'Record<Keys, string>'.
};
Run Code Online (Sandbox Code Playgroud)

以及属性值的类型:

type Keys = "prop1" | "prop2"
type Value = "Hello" | "Aloha"

const obj1: Record<Keys, Value> = {
  prop1: "Hello",
  prop2: "Hey", // TS Error: Type '"Hey"' is not assignable to type 'Value'.
};
Run Code Online (Sandbox Code Playgroud)

  • 正是我所需要的。谢谢!胜利的打字稿! (4认同)

Rya*_*ugh 14

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

var x: { property: string; } = ...;
Run Code Online (Sandbox Code Playgroud)

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

var x = { property: 'hello' };
Run Code Online (Sandbox Code Playgroud)

您的代码正在尝试在值位置使用类型名称.

  • 你的`var x:{property:string; } = ...;`是一个挑逗!我希望省略号是有效的语法,是`var x:{property:string; } = {property:'hello'};`. (9认同)

Log*_*nch 12

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

interface ObjectLiteral {
  [key: string]: any;
}
Run Code Online (Sandbox Code Playgroud)

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

let data: ObjectLiteral = {
  hello: "world",
  goodbye: 1,
  // ...
};
Run Code Online (Sandbox Code Playgroud)

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

祝好运。

  • 这是一个坏主意,它使类型系统变得毫无价值。Typescript 的目的是允许类型系统帮助防止错误,并帮助在工具中提供更好的自动完成功能 - 这基本上禁用了 Typescript 的所有优点。上例中最好不要使用任何接口。 (15认同)
  • @CPHPython 为什么不只指定可选参数及其特定类型?唯一有意义的情况是名称在代码时未知(即它们来自数据库或外部源)。此外,对于复杂的参数组合,联合类型也很有效。如果您针对特定名称进行编码,则应尽可能定义它们。如果只是不影响逻辑的数据,那么当然将其从类型系统中排除。 (6认同)
  • @RickLove我强烈不同意。当多个属性是可选的但我们仍然希望清楚地定义其中的所有类型(例如包含函数的参数)时,这非常有用。这可以简单地视为语法糖,实际上就像接口属性的 **[扩展运算符](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Spread_syntax) **。 (3认同)

muk*_*tel 10

在打字稿中如果我们正在声明对象那么

[access modifier]变量名:{//对象结构}

[access modifier] variable name : { /* structure of object */ }
Run Code Online (Sandbox Code Playgroud)


Tyr*_*ter 8

谨防。对于某些人来说,这似乎是显而易见的,但类型声明:

const foo: TypeName = {}
Run Code Online (Sandbox Code Playgroud)

与以下类型的铸造不同as

const foo = {} as TypeName
Run Code Online (Sandbox Code Playgroud)

尽管建议在其他答案上使用它。

例子:

谢谢,类型安全!:

const foo: { [K in 'open' | 'closed']: string } = {}
// ERROR: TS2739: Type '{}' is missing the following properties from type '{ open: string; closed: string; }': open, closed
Run Code Online (Sandbox Code Playgroud)

再见,类型安全!:

const foo = {} as { [K in 'open' | 'closed']: string }
// No error
Run Code Online (Sandbox Code Playgroud)


Ray*_*oss 7

这就是我在 2021 年使用 TypeScript 4.5 所做的事情:

const sm = {
  reg: {} as ServiceWorkerRegistration,
  quantum: null as number | null,
  currentCacheName: '' as string, // superfluous
  badSWTimer: 0 as number, // superfluous
}
Run Code Online (Sandbox Code Playgroud)

这不仅仅是一个值转换,而且对于对象属性来说,其工作方式与接口定义相同。

更新:我包含了两个多余的类型作为示例。也就是说,这些类型可以自动推断,因此不会生成编译器错误。

来源:4.4 游乐场


小智 6

// 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());
Run Code Online (Sandbox Code Playgroud)

  • 嘿,欢迎来到SO!您能扩展您的答案吗?解释一下这是如何/为什么有效的会很有帮助。 (5认同)

Ego*_*gor 5

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

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

foo({ bar: true, baz: 'lorem ipsum' });
Run Code Online (Sandbox Code Playgroud)


Wil*_*een 5

在你的代码中:

var obj = {
  myProp: string;
};
Run Code Online (Sandbox Code Playgroud)

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

var string = 'A string';

var obj = {
  property: string
};
Run Code Online (Sandbox Code Playgroud)

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

界面:

interface myObj {
    property: string;
}

var obj: myObj = { property: "My string" };
Run Code Online (Sandbox Code Playgroud)

类型别名:

type myObjType = {
    property: string
};

var obj: myObjType = { property: "My string" };
Run Code Online (Sandbox Code Playgroud)

对象类型文字:

var obj: { property: string; } = { property: "Mystring" };
Run Code Online (Sandbox Code Playgroud)


sp3*_*tum 5

从 TypeScript 4.9 开始,satisfies 运算符可用于进行内联断言。您可以将它用于一个值或整个对象,如下所示:

interface NameInfo {
  first: string;
  last: string | undefined;
}
const people = {
  john: { first: "John", last: "Doe" },
  jane: { first: "Jane", last: "Doe" } satisfies NameInfo,
} satisfies Record<string, NameInfo>;
Run Code Online (Sandbox Code Playgroud)

另一种选择是创建一个具有静态属性的类:

class TestData {
  static people: Record<string, NameInfo> = {
    john: { first: "John", last: "Doe" },
    jane: { first: "Jane", last: "Doe" },
  };
}
Run Code Online (Sandbox Code Playgroud)