我想将我的自定义对象分配给 Prisma 包中的 JsonObject efied。这段代码生成错误,我不知道为什么:
interface JsonArray extends Array<JsonValue> {}
type JsonValue = string | number | boolean | JsonObject | JsonArray | null
type JsonObject = {[Key in string]?: JsonValue}
// ^ These are defined in Prisma package and I cannot change them
interface Object {
name: string
}
let object : Object
let jsonObject : JsonObject
// This line has error
jsonObject = object;
// Type 'Object' is not assignable to type 'JsonObject'.
// The 'Object' type is assignable to very few other types.
// Did you mean to use the 'any' type instead?
// Index signature for type 'string' is missing in type 'Object'.ts(2322)
首先,不要命名您的自定义对象类型
Object
。类型 Object
是 Object
值的内置类型。它可能会让人们感到困惑。我不确定您是想更新现有的 Object
类型还是只想创建一些自定义类型,这对于接口来说很重要,因为声明合并。
考虑这个例子:
interface JsonArray extends Array<JsonValue> { }
type JsonValue = string | number | boolean | JsonObject | JsonArray | null
type JsonObject = { [Key in string]?: JsonValue }
interface CustomObject {
name: string
}
declare let object: CustomObject
declare let jsonObject: JsonObject
// This line has error
jsonObject = object;
您遇到的错误意味着
jsonObject
已被索引。换句话说,这意味着您可以使用任何字符串来访问对象值。
例如:
jsonObject['hello'] // ok
然而对于
object
来说则不然。在 object
情况下,您只能使用 name
键来访问适当的值。您不可以使用hello
。
object['hello'] // error
现在,想象一下 TS 允许您执行此操作的情况:
jsonObject = object;
jsonObject['hello'] // undefined, because it has only `name` property
所以,如果你想让它可分配,你应该将索引添加到你的
CustomObject
:
interface CustomObject {
[prop: string]: JsonValue
name: number
}
或者,更有趣的是使用
type
关键字来声明 CustomObject
而不是 interface
:
interface JsonArray extends Array<JsonValue> { }
type JsonValue = string | number | boolean | JsonObject | JsonArray | null
type JsonObject = { [Key in string]?: JsonValue }
type CustomObject= {
name: number
}
declare let object: CustomObject
declare let jsonObject: JsonObject
jsonObject = object; // no error
jsonObject.name
是的,
interface
和type
之间的索引存在差异。请参阅我的答案和文章
请记住,此操作是允许的:
jsonObject['hello'] // undefined but allowed
没有编译器错误,但不安全。
这里有一些问题。
Object
是内置的 JavaScript 数据类型。您应该将您的界面命名为其他名称,例如MyObject
,object
但它没有初始化,即它没有任何值。您不能在操作中使用它,如x = object
,JsonObject
完全重叠。您可以修改界面或使用type
。interface JsonArray extends Array<JsonValue> {}
type JsonValue = string | number | boolean | JsonObject | JsonArray | null
type JsonObject = {[Key in string]?: JsonValue}
// ^ These are defined in Prisma package and I cannot change them
type MyObject = {
name: string
}
let anObject: MyObject = {name: "foo"}
let jsonObject: JsonObject
// no error
jsonObject = anObject
在 typescript 游乐场尝试一下。
我认为之前的答案并没有解决这个常见问题。 Prisma 描述了一种非常通用的 JSON 对象类型(带有索引签名),我们在现实生活中使用的特定类型几乎永远不够通用(想想你使用索引签名的现实生活类型的百分比)。
我的解决方案就是使用类型转换:
myObject as object
。然后它与 Prisma.JsonObject 兼容。
我确信我的对象可以转换为 JSON(例如,我知道它是通过 JSON 从外部 API 接收的,然后进行转换/验证 - 这里可能会出现什么问题?),我只想保存它而不会使代码膨胀,所以我我很确定这是处理这种情况的好方法。
我承认在某些罕见的情况下这不是一个好的解决方案(因为 JS 对象字段不能转换为 JSON,例如在具有循环引用的对象中),但坦率地说,我无法想象一个现实的情况您在 Prisma 中创建一个 Json 类型的字段,然后使用一个无法转换为 JSON 的对象。