在提出问题Typescript custom mapped type之后(感谢Titian Cernicova-Dragomir!)
我有这种映射类型:
export type ToArray<T> = {
[P in keyof T]: T[P] extends Vector<infer U> ? Array<U> : T[P]
}
现在,我想和Pick一起加入。
<Pick<ToArray<Tag>, 'id' | 'name' | 'children' | 'hierarchyName'>>{
id: t.id,
name: t.name,
children: t.children.toArray()
}
但是,编译器不会强迫我添加hierarchyName
,如果我使用,则会发生这种情况:
<Pick<Tag, 'id' | 'name' | 'children' | 'hierarchyName'>>
那怎么样?
答案 0 :(得分:1)
我假设有些定义看起来像您的代码中的定义(您的实际代码可能有所不同,但是此代码足以说明问题):
interface Vector<E> {
elements: E[];
toArray(): E[];
}
interface Tag {
id: string;
name: string;
children: Vector<Tag>;
hierarchyName: string;
}
let t: Tag;
您说的是,在此初始化程序中缺少一个属性时,您将得到预期的错误:
const v1 = <Pick<Tag, 'id' | 'name' | 'children' | 'hierarchyName'>>{
id: t.id,
name: t.name,
children: t.children.toArray()
};
让我们尝试将其简化为一个最小的示例:删除Pick
,并删除所有属性的初始化:
const v2 = <Tag>{
};
没有错误。
为什么?因为<Tag>{}
是type assertion,所以它与{} as Tag
相同-您迫使编译器相信该值实际上具有Tag
类型。
编译器很少报告类型声明的错误,毕竟类型声明是一种告诉编译器“我更了解”的方法。就您而言,仅由于Tag
是递归类型,它具有children
属性(其类型为Tag[]
)而被报告,并且以某种方式使编译器认为值永远不兼容类型:
// error
const v2 = <Tag>{
children: t.children.toArray()
};
使用ToArray
进行转换使类型成为非递归类型:转换后的类型中的children
保留为Tag
类型,这与封闭类型不同,这使得错误消失了。
捕获这些错误的正确方法是对变量声明使用类型注释,而不是类型断言:
const v3: Tag = {}; // error