- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
给定一个简单的对象树,它要么包含其自身类型的值,要么包含需要转换的类型的值:
interface Tree<Leaf> {
[key: string]: Tree<Leaf> | Leaf;
}
function transformTree<S, T>(
obj: Tree<S>,
transform: (value: S) => T,
isLeaf: (value: S | Tree<S>) => boolean
): Tree<T> {
return Object.assign(
{},
...Object.entries(obj).map(([key, value]) => ({
[key]: isLeaf(value)
? transform(value as S)
: transformTree(value as Tree<S>, transform, isLeaf),
}))
);
}
class Wrapper<T> {
constructor(public value: T) {}
}
function transform<T>(wrapped: Wrapper<T>): T {
return wrapped.value;
}
function unwrap<T>(wrapped: Tree<Wrapper<T>>): Tree<T> {
return transformTree<Wrapper<T>, T>(
wrapped,
transform,
(value: Wrapper<T> | Tree<Wrapper<T>>) => value instanceof Wrapper
);
}
const obj = unwrap<string>({
foo: {
bar: new Wrapper("baz"),
},
cow: new Wrapper("moo"),
});
function handleBaz(value: "baz") {
return true;
}
function handleMoo(value: "moo") {
return true;
}
handleBaz(obj.foo.bar); // Error:(162, 19) TS2339: Property 'bar' does not exist on type 'string | Tree<string>'. Property 'bar' does not exist on type 'string'.
handleMoo(obj.cow); //Error:(163, 11) TS2345: Argument of type 'string | Tree<string>' is not assignable to parameter of type '"moo"'. Type 'string' is not assignable to type '"moo"'.
type TransformTree<Leaf, InputTree extends Tree<Leaf>, T> = {
[K in keyof InputTree]: InputTree[K] extends Leaf
? T
: InputTree[K] extends Tree<Leaf>
? TransformTree<Leaf, InputTree[K], T>
: never;
};
type IsLeaf<Leaf> = (value: Tree<Leaf> | Leaf) => boolean;
function transformTree<T extends Tree<From>, From, To>(
tree: T,
transform: (value: From) => To,
isLeaf: IsLeaf<From>
): TransformTree<From, typeof tree, To> {
return Object.assign(
{},
...Object.entries(tree).map(([key, value]) => ({
// XXX have to cast the value in each case, because typescript cannot predict
// the outcome of isLeaf().
[key]: isLeaf(value)
? transform(value as Extract<typeof tree[typeof key], From>)
: transformTree(
value as Extract<typeof tree[typeof key], Tree<From>>,
transform,
isLeaf
),
}))
);
}
function unwrap<T>(
wrapped: Tree<Wrapper<T>>
): TransformTree<Wrapper<T>, typeof wrapped, T> {
return transformTree(
wrapped,
transform,
(value: Wrapper<T> | Tree<Wrapper<T>>) => value instanceof Wrapper
);
}
function handleBaz(value: "baz") {
return true;
}
function handleMoo(value: "moo") {
return true;
}
handleMoo(obj.cow); // OK
handleBaz(obj.foo.bar); // TS2339: Property 'bar' does not exist on type 'never'.
最佳答案
在接下来的内容中,我只会担心打字而不是实现。所有函数将只是 declare
d,好像实际的实现在一些 JS 库中,这些是它们的 declaration files .
另外,您的 isLeaf
函数应该输入为 user-defined type guards其返回类型是类型谓词,而不仅仅是 boolean
.函数签名 isLeaf: (value: S | Tree<S>) => value is S
类似于返回 boolean
,除了编译器实际上会在 if (isLeaf(x)) { x } else { x }
中理解, x
在真正的 block 中将是 S
和 x
在错误 block 中将是 Tree<S>
.
好的,这里开始:
类型Tree<X>
过于笼统,无法跟踪特定的键和值类型。所有编译器都知道该类型的值,例如 Tree<string>
, 是它是一个对象类型,其属性是 string
类型之一或 Tree<string>
.一旦你这样做,说,这个:
const x: Tree<string> = { a: "", b: { c: "", d: { e: "" } } };
string
的任何特定子类型的所有细节。在叶子:
x.a.toUpperCase(); // error
x.z; // no error
Tree<X>
的某些子类型变成
Tree<Y>
的子类型同样的形状,你可以做到。但在最直接的实现中,结果树的所有叶子都是
Y
类型。而不是更窄的类型。我是这样写的:
type TransformTree<T extends Tree<X>, X, Y> = { [K in keyof T]:
T[K] extends X ? Y :
T[K] extends Tree<X> ? TransformTree<T[K], X, Y> :
T[K];
};
declare function transformTree<X, Y, TX extends Tree<X>>(
obj: TX,
transform: (value: X) => Y,
isLeaf: (value: X | Tree<X>) => value is X
): TransformTree<TX, X, Y>;
const t1 = { a: "A", b: { c: "CC", d: { e: "EEE" } } };
const t2 = transformTree(t1,
(x: string) => x.length,
(v): v is string => typeof v === "string"
);
t2.a; // number
t2.b.c; // number
t2.b.d.e; // number
X
到特定类型
Y
,但您想指定一些通用类型函数,如
type F<T extends X> = ...
并从类型
Z extends X
映射叶子至
F<Z>
.
Wrapped<any>
, 你的输出类型函数看起来像
type F<T extends Wrapped<any> = T["value"];
type TransformType<T extends Tree<X>, X, F> = ...
这样的类型函数在哪里
F
本身就是一个带参数的类型函数。这将要求该语言支持所谓的“高级类型”。在
microsoft/TypeScript#1213 上有一个长期开放的功能请求。 ,虽然拥有它们会很棒,但在可预见的将来似乎不会发生。
TransformTree
的特定版本。为他们。例如,如果您的叶类型映射只是索引到单个属性,如
type F<T extends Record<K, any>, K extends PropertyKey> = T[K]
,如您的
Unwrap
情况下,那么你可以这样写:
type TransformTreeIdx<T, X, K extends keyof X> = { [P in keyof T]:
T[P] extends X ? X[K] :
TransformTreeIdx<T[P], X, K>;
};
declare function transformTreeIdx<TX, X, K extends keyof X>(
obj: TX,
key: K,
isLeaf: (value: any) => value is X
): TransformTreeIdx<TX, X, K>;
const w = {
foo: {
bar: new Wrapper("baz" as const),
},
cow: new Wrapper("moo" as const),
};
const w2 = transformTreeIdx(
w, "value", (x: any): x is Wrapper<any> => x instanceof Wrapper
);
handleBaz(w2.foo.bar);
handleMoo(w2.cow);
Wrapper
...映射是转换
Z extends X
进入
Wrapper<Z>
:
type TransformTreeWrap<T, X> = { [P in keyof T]:
T[P] extends X ? Wrapper<T[P]> :
TransformTreeWrap<T[P], X>;
};
declare function transformTreeWrap<TX, X, K extends keyof X>(
obj: TX,
isLeaf: (value: any) => value is X
): TransformTreeWrap<TX, X>;
const u = {
foo: {
bar: "baz" as const,
},
cow: "moo" as const,
};
const u2 = transformTreeWrap(
u, (x: any): x is string => typeof x === "string"
);
handleBaz(u2.foo.bar.value);
handleMoo(u2.cow.value);
isLeaf
/
transform
允许每个节点针对不同的更具体的转换进行测试的对。因此,例如,任何时候您发现
"moo"
输出树中的值
number
并且任何时候您找到
"baz"
输出树中的值
boolean
.
type TransformTreeMap<T, M extends [any, any]> = { [K in keyof T]:
T[K] extends M[0] ? Extract<M, [T[K], any]>[1] :
TransformTreeMap<T[K], M> };
type IsLeafAndTransformer<I, O> = {
isLeaf: (x: any) => x is I,
transform: (x: I) => O
}
type TransformArrayToMap<M extends Array<IsLeafAndTransformer<any, any>>> = {
[K in keyof M]: M[K] extends IsLeafAndTransformer<infer I, infer O> ?
[I, O] : never }[number]
declare function transformTreeMap<T, M extends Array<IsLeafAndTransformer<any, any>>>(
obj: T,
...transformers: M
): TransformTreeMap<T, TransformArrayToMap<M>>;
const mm = transformTreeMap(u,
{ isLeaf: (x: any): x is "moo" => x === "moo", transform: (x: "moo") => 123 },
{ isLeaf: (x: any): x is "baz" => x === "baz", transform: (x: "baz") => true }
);
mm.cow // number
mm.foo.bar // boolean
关于typescript - 在 typescript 中递归转换对象树的所有叶子,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/61253397/
关于 B 树与 B+ 树,网上有一个比较经典的问题:为什么 MongoDb 使用 B 树,而 MySQL 索引使用 B+ 树? 但实际上 MongoDb 真的用的是 B 树吗?
如何将 R* Tree 实现为持久(基于磁盘)树?保存 R* 树索引或保存叶值的文件的体系结构是什么? 注意:此外,如何在这种持久性 R* 树中执行插入、更新和删除操作? 注意事项二:我已经实现了一个
目前,我正在努力用 Java 表示我用 SML 编写的 AST 树,这样我就可以随时用 Java 遍历它。 我想知道是否应该在 Java 中创建一个 Node 类,其中包含我想要表示的数据,以及一个数
我之前用过这个库http://www.cs.umd.edu/~mount/ANN/ .但是,它们不提供范围查询实现。我猜是否有一个 C++ 范围查询实现(圆形或矩形),用于查询二维数据。 谢谢。 最佳
在进一步分析为什么MySQL数据库索引选择使用B+树之前,我相信很多小伙伴对数据结构中的树还是有些许模糊的,因此我们由浅入深一步步探讨树的演进过程,在一步步引出B树以及为什么MySQL数据库索引选择
书接上回,今天和大家一起动手来自己实现树。 相信通过前面的章节学习,大家已经明白树是什么了,今天我们主要针对二叉树,分别使用顺序存储和链式存储来实现树。 01、数组实现 我们在上一节中说过,
书节上回,我们接着聊二叉树,N叉树,以及树的存储。 01、满二叉树 如果一个二叉树,除最后一层节点外,每一层的节点数都达到最大值,即每个节点都有两个子节点,同时所有叶子节点都在最后一层,则这个
树是一种非线性数据结构,是以分支关系定义的层次结构,因此形态上和自然界中的倒挂的树很像,而数据结构中树根向上树叶向下。 什么是树? 01、定义 树是由n(n>=0)个元素节点组成的
操作系统的那棵“树” 今天从一颗 开始,我们看看如何从小树苗长成一颗苍天大树。 运转CPU CPU运转起来很简单,就是不断的从内存取值执行。 CPU没有好好运转 IO是个耗费时间的活,如果CPU在取值
我想为海洋生物学类(class)制作一个简单的系统发育树作为教育示例。我有一个具有分类等级的物种列表: Group <- c("Benthos","Benthos","Benthos","Be
我从这段代码中删除节点时遇到问题,如果我插入数字 12 并尝试删除它,它不会删除它,我尝试调试,似乎当它尝试删除时,它出错了树的。但是,如果我尝试删除它已经插入主节点的节点,它将删除它,或者我插入数字
B+ 树的叶节点链接在一起。将 B+ 树的指针结构视为有向图,它不是循环的。但是忽略指针的方向并将其视为链接在一起的无向叶节点会在图中创建循环。 在 Haskell 中,如何将叶子构造为父内部节点的子
我在 GWT 中使用树控件。我有一个自定义小部件,我将其添加为 TreeItem: Tree testTree = new Tree(); testTree.addItem(myWidget); 我想
它有点像混合树/链表结构。这是我定义结构的方式 struct node { nodeP sibling; nodeP child; nodeP parent; char
我编写了使用队列遍历树的代码,但是下面的出队函数生成错误,head = p->next 是否有问题?我不明白为什么这部分是错误的。 void Levelorder(void) { node *tmp,
例如,我想解析以下数组: var array1 = ["a.b.c.d", "a.e.f.g", "a.h", "a.i.j", "a.b.k"] 进入: var json1 = { "nod
问题 -> 给定一棵二叉树和一个和,确定该树是否具有从根到叶的路径,使得沿路径的所有值相加等于给定的和。 我的解决方案 -> public class Solution { public bo
我有一个创建 java 树的任务,它包含三列:运动名称、运动类别中的运动计数和上次更新。类似的东西显示在下面的图像上: 如您所见,有 4 种运动:水上运动、球类运动、跳伞运动和舞蹈运动。当我展开 sk
我想在 H2 数据库中实现 B+ Tree,但我想知道,B+ Tree 功能在 H2 数据库中可用吗? 最佳答案 H2 已经使用了 B+ 树(PageBtree 类)。 关于mysql - H2数据库
假设我们有 5 个字符串数组: String[] array1 = {"hello", "i", "cat"}; String[] array2 = {"hello", "i", "am"}; Str
我是一名优秀的程序员,十分优秀!