如何实现匹配静态接口的Jsonabilible类型?

问题描述 投票:0回答:1

在 Typescript 中,所有这 3 种类型都很相似,因为它们仅由原始类型、映射和数组组成:

type Color1 = { [component: string]: number }

type Color2 = {
  green: number
  red: number
  blue: number
}

interface Color3 {
  green: number
  red: number
  blue: number
}

如何设计一种符合上述所有定义的类型?

明显的定义不适用于

Color3

type JsonPrimitive = string | number | boolean | null
type JsonifiableObject = { [Key in string]?: Jsonifiable }
type JsonifiableArray = readonly Jsonifiable[]
type Jsonifiable = JsonPrimitive | JsonifiableObject | JsonifiableArray

const color1 = {green: 1, red: 2, blue: 3} as Color1 as Jsonifiable
const color2 = {green: 1, red: 2, blue: 3} as Color2 as Jsonifiable
const color3 = {green: 1, red: 2, blue: 3} as Color3 as Jsonifiable

产量:

Conversion of type 'Color3' to type 'Jsonifiable' may be a mistake because neither type sufficiently overlaps with the other. If this was intentional, convert the expression to 'unknown' first.
  Type 'Color3' is not comparable to type 'JsonifiableObject'.
    Index signature for type 'string' is missing in type 'Color3'.
typescript types
1个回答
0
投票

没有特定的类型可以按照您想要的方式工作。如果您有一个带有

string
索引签名(例如
JsonifiableObject
)的对象类型(应该是
{[k: string]: Jsonifiable}
或者可能是
{[k: string]: Jsonifiable | undefined}
,具体取决于您是否真的想要使用
?
修饰符),那么它永远不会与缺乏索引签名的接口兼容。也就是说,接口给出隐式索引签名。这记录在 microsoft/TypeScript#15300 中,并且是经过设计考虑的。

你要么需要放弃,要么想办法解决它。


如果您需要将接口类型与此类相匹配,则需要将索引签名更改为 generic 键,这意味着您的

Jsonifiable
类型将变为
JsonifiableValidate<T>
类型,使得
T extends JsonifiableValidate<T>
如果并且仅当
T
有效时。它变得像一个通用的约束

type JsonifiableValidate<T> = T extends JsonPrimitive ? T :
    T extends readonly (infer A)[] ? readonly (JsonifiableValidate<A>)[] :
    T extends Function ? never :
    T extends object ? { [K in keyof T]: JsonifiableValidate<T[K]> } : never;

并且由于泛型类型没有类型参数推断(这是microsoft/TypeScript#32794中记录的缺失功能),您需要创建一个如下所示的泛型帮助器标识函数:

const jsonifiable = <T,>(t: JsonifiableValidate<T>) => t;

然后你写下

const color: Jsonifiable = {⋯}
而不是
const color = jsonifiable({⋯})

const color = jsonifiable({ green: 1, red: 2, blue: 3 } as Color3); // okay

Playground 代码链接

© www.soinside.com 2019 - 2024. All rights reserved.