fix: refine isContainer & getType

This commit is contained in:
Zixuan Chen 2023-12-05 14:28:39 +08:00
parent acdcb14367
commit d9d28ada61
No known key found for this signature in database
2 changed files with 92 additions and 10 deletions

View file

@ -1,5 +1,5 @@
export * from "loro-wasm";
import { Container, ContainerType, Delta, OpId, Value } from "loro-wasm";
import { Container, ContainerType, Delta, LoroText, LoroTree, OpId, Value } from "loro-wasm";
import { PrelimText, PrelimList, PrelimMap } from "loro-wasm";
import { ContainerID, Loro, LoroList, LoroMap, TreeID } from "loro-wasm";
@ -89,8 +89,8 @@ export type MapDiff = {
export type TreeDiff = {
type: "tree";
diff:
| { target: TreeID; action: "create" | "delete" }
| { target: TreeID; action: "move"; parent: TreeID };
| { target: TreeID; action: "create" | "delete" }
| { target: TreeID; action: "move"; parent: TreeID };
};
export type Diff = ListDiff | TextDiff | MapDiff | TreeDiff;
@ -107,21 +107,61 @@ export function isContainerId(s: string): s is ContainerID {
export { Loro };
/** Whether the value is a container.
*
* # Example
*
* ```ts
* const doc = new Loro();
* const map = doc.getMap("map");
* const list = doc.getList("list");
* const text = doc.getText("text");
* isContainer(map); // true
* isContainer(list); // true
* isContainer(text); // true
* isContainer(123); // false
* isContainer("123"); // false
* isContainer({}); // false
*/
export function isContainer(value: any): value is Container {
if (typeof value !== "object" || value == null) {
return false;
}
const p = value.__proto__;
return p.hasOwnProperty("kind") && CONTAINER_TYPES.includes(value.kind());
if (p == null || typeof p !== "object" || typeof p["kind"] !== "function") {
return false;
}
return CONTAINER_TYPES.includes(value.kind());
}
export function valueType(value: any): "Json" | ContainerType {
/** Get the type of a value that may be a container.
*
* # Example
*
* ```ts
* const doc = new Loro();
* const map = doc.getMap("map");
* const list = doc.getList("list");
* const text = doc.getText("text");
* getType(map); // "Map"
* getType(list); // "List"
* getType(text); // "Text"
* getType(123); // "Json"
* getType("123"); // "Json"
* getType({}); // "Json"
* ```
*/
export function getType<T>(value: T): T extends LoroText ? "Text" :
T extends LoroMap ? "Map" :
T extends LoroTree ? "Tree" :
T extends LoroList ? "List" : "Json" {
if (isContainer(value)) {
return value.kind();
}
return "Json";
return "Json" as any;
}
declare module "loro-wasm" {

View file

@ -1,4 +1,4 @@
import { describe, expect, it } from "vitest";
import { describe, expect, expectTypeOf, it } from "vitest";
import {
Loro,
LoroList,
@ -6,7 +6,7 @@ import {
isContainer,
setPanicHook,
toEncodedVersion,
valueType,
getType,
} from "../src";
import { Container } from "../dist/loro";
@ -106,8 +106,8 @@ describe("list", () => {
list.insertContainer(2, "Text");
const t = list.toArray()[2];
expect(isContainer(t)).toBeTruthy();
expect(valueType(t)).toBe("Text");
expect(valueType(123)).toBe("Json");
expect(getType(t)).toBe("Text");
expect(getType(123)).toBe("Json");
});
});
@ -241,3 +241,45 @@ it("handlers should still be usable after doc is dropped", () => {
expect(map.toJson()).toStrictEqual({ k: 8 });
});
it("isContainer", () => {
expect(isContainer("123")).toBeFalsy();
expect(isContainer(123)).toBeFalsy();
expect(isContainer(123n)).toBeFalsy();
expect(isContainer(new Map())).toBeFalsy();
expect(isContainer(new Set())).toBeFalsy();
expect(isContainer({})).toBeFalsy();
expect(isContainer(undefined)).toBeFalsy();
expect(isContainer(null)).toBeFalsy();
const doc = new Loro();
const t = doc.getText("t");
expect(isContainer(t)).toBeTruthy();
expect(getType(t)).toBe("Text");
expect(getType(123)).toBe("Json");
})
it("getValueType", () => {
// Type tests
const doc = new Loro();
const t = doc.getText("t");
expectTypeOf(getType(t)).toEqualTypeOf<"Text">();
expect(getType(t)).toBe("Text");
expectTypeOf(getType(123)).toEqualTypeOf<"Json">();
expect(getType(123)).toBe("Json");
expectTypeOf(getType(undefined)).toEqualTypeOf<"Json">();
expect(getType(undefined)).toBe("Json");
expectTypeOf(getType(null)).toEqualTypeOf<"Json">();
expect(getType(null)).toBe("Json");
expectTypeOf(getType({})).toEqualTypeOf<"Json">();
expect(getType({})).toBe("Json");
const map = doc.getMap("map");
const list = doc.getList("list");
const tree = doc.getTree("tree");
expectTypeOf(getType(map)).toEqualTypeOf<"Map">();
expect(getType(map)).toBe("Map");
expectTypeOf(getType(list)).toEqualTypeOf<"List">();
expect(getType(list)).toBe("List");
expectTypeOf(getType(tree)).toEqualTypeOf<"Tree">();
expect(getType(tree)).toBe("Tree");
})