ChatGPT解决这个技术问题 Extra ChatGPT

TypeScript 中对象字面量中的类型定义

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

class className {
  property: string;
};

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

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

var obj = {
  property: string;
};

我收到以下错误:

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

我做错了什么还是这是一个错误?


T
Timothy Perez

您非常接近,您只需将 = 替换为 :。您可以使用对象类型文字(参见规范第 3.5.3 节)或接口。使用对象类型文字接近于您所拥有的:

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

但是你也可以使用一个接口

interface MyObjLayout {
    property: string;
}

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

@Rick Love 与演员表操作员的 DRY(不要重复自己)选项似乎更整洁。只是评论,而不是投票...
我知道这已经回答了一段时间,但是当类具有方法和属性时可能会出现问题的假设我错了吗?由于类没有被初始化并且我们只分配属性,调用类上的方法将导致空异常。基本上,我们创建的对象只是“充当”类,因为我们分配了它的类型,但它实际上并不是该类的实例。即我们需要使用'new' 关键字创建类。然后我们回到第一格,因为我们不能做像 new class() {prop: 1}; 这样的事情。例如,在 TS 中就像我们在 C# 中一样。
@DeuxAlpha 这是分配给一个不能有方法的接口。我不相信你可以分配到这样的班级。
链接到规范会很好:)
@DeuxAlpha 这是创建一个对象文字,而不是一个类对象。接口也可以有方法。如果你的接口定义了一个方法,那么对象字面量也必须定义它——它不会为空。对象字面量必须满足接口定义的所有内容,否则类型系统将显示错误。
R
Rick Love

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 中,确保启用严格的 null 检查:

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

对 TSX 使用 as 运算符。

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,
};

如果您使用的是 TSX(TS 与 JSX),则不能使用尖括号命名,因此这些行类似于 property: null as string,其中重要的区别是 as 运算符。
@RickLove这是否实际上限制了对象变量的类型,或者这只是在分配时指定类型的一种方式?换句话说,在第二个示例中分配给变量 call 之后,您可以为其分配完全不同的类型吗?
这应该是答案
不工作。 Error:(33, 15) TS2352:Type 'null' cannot be converted to type 'string'.
这只是对语言功能的滥用还是实际上是合法的?您能否提供阅读官方文档的链接?谢谢!
L
LogicalBranch

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

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

然后你会使用它,像这样:

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

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

祝你好运。


这是一个坏主意,它使类型系统一文不值。 typescript 的重点是允许类型系统帮助防止错误,并帮助在工具中提供更好的自动完成功能 - 这基本上禁用了 Typescript 的所有好处。在上面的例子中最好不要使用任何接口。
@RickLove 我强烈反对。这在几个属性是可选的但我们仍然想清楚地定义其中的所有类型(例如,包含函数的参数)时非常有用。这可以简单地视为语法糖,实际上就像 spread operator 用于接口的属性
@CPHPython 为什么不直接指定具有特定类型的可选参数?唯一有意义的情况是在代码时不知道名称(即它们来自数据库或外部源)。同样对于复杂的参数组合,联合类型也很有效。如果您针对特定名称进行编码,则应尽可能定义它们。如果只是不影响逻辑的数据,那么当然将其排除在类型系统之外。
@RickLove“代码时名称未知”->这是一个很好的实用示例,这些键类型的值是已知的并且它们都是相同的(例如 string)。请注意,我只是提倡使用 [key: string] 部分,而不是 any 部分作为值的类型定义......这确实会消除类型的用处。
如果我想允许添加字符串和数字但不允许添加其他类型,我该怎么做?
s
streletss

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

const obj: Record<string, string> = {
  property: "value",
};

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

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>'.
};

以及属性值的类型:

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'.
};

正是我需要的。谢谢!打字稿赢了!
我也会在这里使用 let 而不是 var
如果您有动态类型,请使用它。
H
Hugo Elhaj-Lahsen

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

var x: { property: string; } = { property: 'hello' };

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

var x = { property: 'hello' };

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


E
Egor

如果您尝试将类型添加到解构的对象文字中,例如在函数的参数中,则语法为:

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

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

L
LogicalBranch

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

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

例如:

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

A
Audwin Oyong

谨防。这对某些人来说似乎很明显,但类型声明:

const foo: TypeName = {}

与使用 as 进行强制转换相比不一样:

const foo = {} as TypeName

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

例子:

谢谢,类型安全!:

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

再见,类型安全!:

const foo = {} as { [K in 'open' | 'closed']: string }
// No error

H
Hamza Ibrahim
// 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());

嘿,欢迎来到 SO!您能否完全扩展您的答案,这将有助于解释其工作原理/原因。
R
Ray Foss

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

const sm = {
  reg: {} as ServiceWorkerRegistration,
  quantum: null as number | null,
  currentCacheName: '' as string, // superfluous
  badSWTimer: 0 as number, // superfluous
}

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

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

来源:4.4 Playground


你能链接一个 TS 4.5 参考吗? (特别是对于“不仅仅是价值转换”部分。)
@JanMolnar 非常感谢...请参阅源链接
谢谢你。不幸的是,我没有看到提到的 TS 4.5、链接 4.4 和旧的 3.3 之间有什么区别,所以我不知道 2021 年的新事物是什么。也许“自 2012 年以来的新事物”是指,而不是 2021 年。
我认为您不应该真正使用 as
W
Willem van der Veen

在您的代码中:

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: { property: string; } = { property: "Mystring" };

A
Akhil Sharma

使用 type 关键字创建类型

type ObjType = {
  property: string;
}

然后您可以使用它来绑定您的对象以仅接受这种类型,如下所示。

const obj: ObjType = {
property: "TypeScript"
}

Z
Zoman

只是为了扩展@RickLove 的回复......

这很好用,因为您只需要定义无法推断的类型:

const initialState = { 
   user: undefined as User | undefined, 
   userLoading: false
}; 

它转译成这个 js 代码:

const initialState = { 
   user: undefined, 
   userLoading: false
};  

如果你需要将它提取到一个类型中,你可以这样做:

export type InitState = typeof initialState;

C
CarbonDry

使用 DRY 将对象文字转换为类型

做就是了:

const myObject = {
   hello: 'how are you',
   hey: 'i am fine thank you'
}
type myObjectType = keyof typeof MyObject

任务完成!