aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/client/util/UndoManager.ts4
-rw-r--r--src/client/views/nodes/AudioBox.tsx27
-rw-r--r--src/client/views/nodes/DocumentView.tsx190
-rw-r--r--src/client/views/nodes/FormattedTextBox.tsx28
-rw-r--r--src/new_fields/Doc.ts11
-rw-r--r--src/new_fields/Schema.ts13
-rw-r--r--src/new_fields/Types.ts12
7 files changed, 133 insertions, 152 deletions
diff --git a/src/client/util/UndoManager.ts b/src/client/util/UndoManager.ts
index 27aed4bac..f91ca2e06 100644
--- a/src/client/util/UndoManager.ts
+++ b/src/client/util/UndoManager.ts
@@ -1,4 +1,4 @@
-import { observable, action } from "mobx";
+import { observable, action, runInAction } from "mobx";
import 'source-map-support/register';
import { Without } from "../../Utils";
import { string } from "prop-types";
@@ -143,7 +143,7 @@ export namespace UndoManager {
export function RunInBatch(fn: () => void, batchName: string) {
let batch = StartBatch(batchName);
try {
- fn();
+ runInAction(fn);
} finally {
batch.end();
}
diff --git a/src/client/views/nodes/AudioBox.tsx b/src/client/views/nodes/AudioBox.tsx
index 1493ff25b..be12dced3 100644
--- a/src/client/views/nodes/AudioBox.tsx
+++ b/src/client/views/nodes/AudioBox.tsx
@@ -1,36 +1,19 @@
import React = require("react");
import { FieldViewProps, FieldView } from './FieldView';
-import { FieldWaiting } from '../../../fields/Field';
import { observer } from "mobx-react";
-import { ContextMenu } from "../../views/ContextMenu";
-import { observable, action } from 'mobx';
-import { KeyStore } from '../../../fields/KeyStore';
-import { AudioField } from "../../../fields/AudioField";
import "./AudioBox.scss";
-import { NumberField } from "../../../fields/NumberField";
+import { Cast } from "../../../new_fields/Types";
+import { AudioField } from "../../../new_fields/URLField";
+const defaultField: AudioField = new AudioField(new URL("http://techslides.com/demos/samples/sample.mp3"));
@observer
export class AudioBox extends React.Component<FieldViewProps> {
public static LayoutString() { return FieldView.LayoutString(AudioBox); }
- constructor(props: FieldViewProps) {
- super(props);
- }
-
-
-
- componentDidMount() {
- }
-
- componentWillUnmount() {
- }
-
-
render() {
- let field = this.props.Document.Get(this.props.fieldKey);
- let path = field === FieldWaiting ? "http://techslides.com/demos/samples/sample.mp3" :
- field instanceof AudioField ? field.Data.href : "http://techslides.com/demos/samples/sample.mp3";
+ let field = Cast(this.props.Document[this.props.fieldKey], AudioField, defaultField);
+ let path = field.url.href;
return (
<div>
diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx
index c0afc192e..e00f56d53 100644
--- a/src/client/views/nodes/DocumentView.tsx
+++ b/src/client/views/nodes/DocumentView.tsx
@@ -18,9 +18,20 @@ import "./DocumentView.scss";
import React = require("react");
import { Field, Opt, Doc, Id } from "../../../new_fields/Doc";
import { DocComponent } from "../DocComponent";
-import { createSchema, makeInterface } from "../../../new_fields/Schema";
-import { FieldValue } from "../../../new_fields/Types";
+import { createSchema, makeInterface, listSpec } from "../../../new_fields/Schema";
+import { FieldValue, Cast, PromiseValue } from "../../../new_fields/Types";
+import { List } from "../../../new_fields/List";
+
+const linkSchema = createSchema({
+ title: "string",
+ linkDescription: "string",
+ linkTags: "string",
+ linkedTo: Doc,
+ linkedFrom: Doc
+});
+type LinkDoc = makeInterface<[typeof linkSchema]>;
+const LinkDoc = makeInterface(linkSchema);
export interface DocumentViewProps {
ContainingCollectionView: Opt<CollectionView | CollectionPDFView | CollectionVideoView>;
@@ -157,16 +168,14 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
e.stopPropagation();
if (!SelectionManager.IsSelected(this) && e.button !== 2) {
if (Math.abs(e.clientX - this._downX) < 4 && Math.abs(e.clientY - this._downY) < 4) {
- if (this.props.Document.Get(KeyStore.MaximizedDoc) instanceof Document) {
- this.props.Document.GetAsync(KeyStore.MaximizedDoc, maxdoc => {
- if (maxdoc instanceof Document) {
- this.props.addDocument && this.props.addDocument(maxdoc, false);
- this.toggleMinimize(maxdoc, this.props.Document);
- }
- });
- } else {
- SelectionManager.SelectDoc(this, e.ctrlKey);
- }
+ PromiseValue(Cast(this.props.Document.maximizedDoc, Doc)).then(maxdoc => {
+ if (maxdoc instanceof Doc) {
+ this.props.addDocument && this.props.addDocument(maxdoc, false);
+ this.toggleMinimize(maxdoc, this.props.Document);
+ } else {
+ SelectionManager.SelectDoc(this, e.ctrlKey);
+ }
+ });
}
}
}
@@ -184,7 +193,10 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
}
}
fullScreenClicked = (e: React.MouseEvent): void => {
- CollectionDockingView.Instance.OpenFullScreen(Doc.MakeDelegate(this.Document.prototype));
+ const doc = Doc.MakeDelegate(FieldValue(this.Document.proto));
+ if (doc) {
+ CollectionDockingView.Instance.OpenFullScreen(doc);
+ }
ContextMenu.Instance.clearItems();
ContextMenu.Instance.addItem({ description: "Close Full Screen", event: this.closeFullScreenClicked });
ContextMenu.Instance.displayMenu(e.pageX - 15, e.pageY - 15);
@@ -197,39 +209,39 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
ContextMenu.Instance.displayMenu(e.pageX - 15, e.pageY - 15);
}
- @action createIcon = (layoutString: string): Document => {
- let iconDoc = Documents.IconDocument(layoutString);
- iconDoc.SetBoolean(KeyStore.IsMinimized, false);
- iconDoc.SetNumber(KeyStore.NativeWidth, 0);
- iconDoc.SetNumber(KeyStore.NativeHeight, 0);
- iconDoc.Set(KeyStore.Prototype, this.props.Document);
- iconDoc.Set(KeyStore.MaximizedDoc, this.props.Document);
- this.props.Document.Set(KeyStore.MinimizedDoc, iconDoc);
+ @action createIcon = (layoutString: string): Doc => {
+ let iconDoc: Doc = Documents.IconDocument(layoutString);
+ iconDoc.isMinimized = false;
+ iconDoc.nativeWidth = 0;
+ iconDoc.nativeHeight = 0;
+ iconDoc.proto = this.props.Document;
+ iconDoc.maximizedDoc = this.props.Document;
+ this.Document.minimizedDoc = iconDoc;
this.props.addDocument && this.props.addDocument(iconDoc, false);
return iconDoc;
}
- animateTransition(icon: number[], targ: number[], width: number, height: number, stime: number, target: Document, maximizing: boolean) {
+ animateTransition(icon: number[], targ: number[], width: number, height: number, stime: number, target: Doc, maximizing: boolean) {
setTimeout(() => {
let now = Date.now();
let progress = Math.min(1, (now - stime) / 200);
let pval = maximizing ?
[icon[0] + (targ[0] - icon[0]) * progress, icon[1] + (targ[1] - icon[1]) * progress] :
[targ[0] + (icon[0] - targ[0]) * progress, targ[1] + (icon[1] - targ[1]) * progress];
- target.SetNumber(KeyStore.Width, maximizing ? 25 + (width - 25) * progress : width + (25 - width) * progress);
- target.SetNumber(KeyStore.Height, maximizing ? 25 + (height - 25) * progress : height + (25 - height) * progress);
- target.SetNumber(KeyStore.X, pval[0]);
- target.SetNumber(KeyStore.Y, pval[1]);
+ target.width = maximizing ? 25 + (width - 25) * progress : width + (25 - width) * progress;
+ target.height = maximizing ? 25 + (height - 25) * progress : height + (25 - height) * progress;
+ target.x = pval[0];
+ target.y = pval[1];
if (now < stime + 200) {
this.animateTransition(icon, targ, width, height, stime, target, maximizing);
}
else {
if (!maximizing) {
- target.SetBoolean(KeyStore.IsMinimized, true);
- target.SetNumber(KeyStore.X, targ[0]);
- target.SetNumber(KeyStore.Y, targ[1]);
- target.SetNumber(KeyStore.Width, width);
- target.SetNumber(KeyStore.Height, height);
+ target.isMinimized = true;
+ target.x = targ[0];
+ target.y = targ[1];
+ target.width = width;
+ target.height = height;
}
this._completed = true;
}
@@ -240,83 +252,71 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
_completed = true;
@action
- public toggleMinimize = (maximized: Document, minim: Document): void => {
+ public toggleMinimize = (maximized: Doc, minim: Doc): void => {
SelectionManager.DeselectAll();
- if (maximized instanceof Document && this._completed) {
+ if (this._completed) {
this._completed = false;
- let minimized = maximized.GetBoolean(KeyStore.IsMinimized, false);
- maximized.SetBoolean(KeyStore.IsMinimized, false);
+ let minimized = Cast(maximized.isMinimized, "boolean", false);
+ maximized.isMinimized = false;
this.animateTransition(
- [minim.GetNumber(KeyStore.X, 0), minim.GetNumber(KeyStore.Y, 0)],
- [maximized.GetNumber(KeyStore.X, 0), maximized.GetNumber(KeyStore.Y, 0)],
- maximized.GetNumber(KeyStore.Width, 0), maximized.GetNumber(KeyStore.Height, 0),
+ [Cast(minim.x, "number", 0), Cast(minim.y, "number", 0)],
+ [Cast(maximized.x, "number", 0), Cast(maximized.y, "number", 0)],
+ Cast(maximized.width, "number", 0), Cast(maximized.width, "number", 0),
Date.now(), maximized, minimized);
}
}
@action
- public minimize = (): void => {
- this.props.Document.GetAsync(KeyStore.MinimizedDoc, mindoc => {
- if (mindoc === undefined) {
- this.props.Document.GetAsync(KeyStore.BackgroundLayout, field => {
- if (field instanceof TextField) {
- this.toggleMinimize(this.props.Document, this.createIcon(field.Data));
- }
- else this.props.Document.GetAsync(KeyStore.Layout, field => {
- if (field instanceof TextField) {
- this.createIcon(field.Data);
- this.toggleMinimize(this.props.Document, this.createIcon(field.Data));
- }
- });
- });
- }
- else if (mindoc instanceof Document) {
- this.props.addDocument && this.props.addDocument(mindoc, false);
- this.toggleMinimize(this.props.Document, mindoc);
+ public minimize = async (): Promise<void> => {
+ const mindoc = await Cast(this.props.Document.minimizedDoc, Doc);
+ if (mindoc === undefined) {
+ const background = await Cast(this.props.Document.backgroundLayout, "string");
+ if (background === undefined) {
+ const layout = await Cast(this.props.Document.layout, "string");
+ if (layout) {
+ this.createIcon(layout);
+ this.toggleMinimize(this.props.Document, this.createIcon(layout));
+ }
+ } else {
+ this.toggleMinimize(this.props.Document, this.createIcon(background));
}
- });
+ } else {
+ this.props.addDocument && this.props.addDocument(mindoc, false);
+ this.toggleMinimize(this.props.Document, mindoc);
+ }
}
@undoBatch
@action
- drop = (e: Event, de: DragManager.DropEvent) => {
+ drop = async (e: Event, de: DragManager.DropEvent) => {
if (de.data instanceof DragManager.LinkDragData) {
- let sourceDoc: Document = de.data.linkSourceDocument;
- let destDoc: Document = this.props.Document;
- let linkDoc: Document = new Document();
-
- destDoc.GetTAsync(KeyStore.Prototype, Document).then(protoDest =>
- sourceDoc.GetTAsync(KeyStore.Prototype, Document).then(protoSrc =>
- runInAction(() => {
- let batch = UndoManager.StartBatch("document view drop");
- linkDoc.SetText(KeyStore.Title, "New Link");
- linkDoc.SetText(KeyStore.LinkDescription, "");
- linkDoc.SetText(KeyStore.LinkTags, "Default");
-
- let dstTarg = protoDest ? protoDest : destDoc;
- let srcTarg = protoSrc ? protoSrc : sourceDoc;
- linkDoc.Set(KeyStore.LinkedToDocs, dstTarg);
- linkDoc.Set(KeyStore.LinkedFromDocs, srcTarg);
- const prom1 = new Promise(resolve => dstTarg.GetOrCreateAsync(
- KeyStore.LinkedFromDocs,
- ListField,
- field => {
- (field as ListField<Document>).Data.push(linkDoc);
- resolve();
- }
- ));
- const prom2 = new Promise(resolve => srcTarg.GetOrCreateAsync(
- KeyStore.LinkedToDocs,
- ListField,
- field => {
- (field as ListField<Document>).Data.push(linkDoc);
- resolve();
- }
- ));
- Promise.all([prom1, prom2]).finally(() => batch.end());
- })
- )
- );
+ let sourceDoc: Doc = de.data.linkSourceDocument;
+ let destDoc: Doc = this.props.Document;
+ let linkDoc = LinkDoc();
+
+ const protoDest = await Cast(destDoc.proto, Doc);
+ const protoSrc = await Cast(sourceDoc.proto, Doc);
+ UndoManager.RunInBatch(() => {
+ linkDoc.title = "New Link";
+ linkDoc.linkDescription = "";
+ linkDoc.linkTags = "Default";
+
+ let dstTarg = protoDest ? protoDest : destDoc;
+ let srcTarg = protoSrc ? protoSrc : sourceDoc;
+ linkDoc.linkedTo = dstTarg;
+ linkDoc.linkedFrom = srcTarg;
+ let linkedFrom = Cast(dstTarg.linkedFrom, listSpec(Doc));
+ if (!linkedFrom) {
+ dstTarg.linkedFrom = linkedFrom = new List<Doc>();
+ }
+ linkedFrom.push(linkDoc);
+
+ let linkedTo = Cast(srcTarg.linkedTo, listSpec(Doc));
+ if (!linkedTo) {
+ srcTarg.linkedTo = linkedTo = new List<Doc>();
+ }
+ linkedTo.push(linkDoc);
+ }, "document view drop");
e.stopPropagation();
}
}
@@ -361,7 +361,7 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
@computed get nativeWidth() { return FieldValue(this.Document.nativeWidth) || 0; }
@computed get nativeHeight() { return FieldValue(this.Document.nativeHeight) || 0; }
- @computed get contents() { return (<DocumentContentsView {...this.props} isSelected={this.isSelected} select={this.select} layoutKey={KeyStore.Layout} />); }
+ @computed get contents() { return (<DocumentContentsView {...this.props} isSelected={this.isSelected} select={this.select} layoutKey={"layout"} />); }
render() {
diff --git a/src/client/views/nodes/FormattedTextBox.tsx b/src/client/views/nodes/FormattedTextBox.tsx
index 639dae30a..cb082dc69 100644
--- a/src/client/views/nodes/FormattedTextBox.tsx
+++ b/src/client/views/nodes/FormattedTextBox.tsx
@@ -4,11 +4,6 @@ import { history } from "prosemirror-history";
import { keymap } from "prosemirror-keymap";
import { EditorState, Plugin, Transaction } from "prosemirror-state";
import { EditorView } from "prosemirror-view";
-import { FieldWaiting, Opt } from "../../../fields/Field";
-import { KeyStore } from "../../../fields/KeyStore";
-import { RichTextField } from "../../../fields/RichTextField";
-import { TextField } from "../../../fields/TextField";
-import { Document } from "../../../fields/Document";
import buildKeymap from "../../util/ProsemirrorKeymap";
import { inpRules } from "../../util/RichTextRules";
import { schema } from "../../util/RichTextSchema";
@@ -20,6 +15,9 @@ import { FieldView, FieldViewProps } from "./FieldView";
import "./FormattedTextBox.scss";
import React = require("react");
import { SelectionManager } from "../../util/SelectionManager";
+import { DocComponent } from "../DocComponent";
+import { createSchema, makeInterface } from "../../../new_fields/Schema";
+import { Opt, Doc } from "../../../new_fields/Doc";
const { buildMenuItems } = require("prosemirror-example-setup");
const { menuBar } = require("prosemirror-menu");
@@ -44,7 +42,14 @@ export interface FormattedTextBoxOverlay {
isOverlay?: boolean;
}
-export class FormattedTextBox extends React.Component<(FieldViewProps & FormattedTextBoxOverlay)> {
+const richTextSchema = createSchema({
+ documentText: "string"
+});
+
+type RichTextDocument = makeInterface<[typeof richTextSchema]>;
+const RichTextDocument = makeInterface(richTextSchema);
+
+export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTextBoxOverlay), RichTextDocument>(RichTextDocument) {
public static LayoutString(fieldStr: string = "DataKey") {
return FieldView.LayoutString(FormattedTextBox, fieldStr);
}
@@ -59,7 +64,6 @@ export class FormattedTextBox extends React.Component<(FieldViewProps & Formatte
super(props);
this._ref = React.createRef();
- this.onChange = this.onChange.bind(this);
}
_applyingChange: boolean = false;
@@ -74,7 +78,7 @@ export class FormattedTextBox extends React.Component<(FieldViewProps & Formatte
JSON.stringify(state.toJSON()),
RichTextField
);
- this.props.Document.SetDataOnPrototype(KeyStore.DocumentText, state.doc.textBetween(0, state.doc.content.size, "\n\n"), TextField);
+ Doc.SetOnPrototype(this.props.Document, "documentText", state.doc.textBetween(0, state.doc.content.size, "\n\n"));
this._applyingChange = false;
// doc.SetData(fieldKey, JSON.stringify(state.toJSON()), RichTextField);
}
@@ -166,12 +170,6 @@ export class FormattedTextBox extends React.Component<(FieldViewProps & Formatte
}
}
- @action
- onChange(e: React.ChangeEvent<HTMLInputElement>) {
- const { fieldKey, Document } = this.props;
- Document.SetOnPrototype(fieldKey, new RichTextField(e.target.value));
- // doc.SetData(fieldKey, e.target.value, RichTextField);
- }
onPointerDown = (e: React.PointerEvent): void => {
if (e.button === 1 && this.props.isSelected() && !e.altKey && !e.ctrlKey && !e.metaKey) {
console.log("first");
@@ -252,7 +250,7 @@ export class FormattedTextBox extends React.Component<(FieldViewProps & Formatte
}
onKeyPress(e: React.KeyboardEvent) {
- if (e.key == "Escape") {
+ if (e.key === "Escape") {
SelectionManager.DeselectAll();
}
e.stopPropagation();
diff --git a/src/new_fields/Doc.ts b/src/new_fields/Doc.ts
index 60abccce6..5ae095e68 100644
--- a/src/new_fields/Doc.ts
+++ b/src/new_fields/Doc.ts
@@ -33,8 +33,8 @@ export class ObjectField {
export type Field = number | string | boolean | ObjectField | RefField;
export type Opt<T> = T | undefined;
-export type FieldWaiting<T extends Field = Field> = Promise<T | undefined>;
-export type FieldResult<T extends Field = Field> = Opt<T> | FieldWaiting<T>;
+export type FieldWaiting<T extends RefField = RefField> = T extends undefined ? never : Promise<T | undefined>;
+export type FieldResult<T extends Field = Field> = Opt<T> | FieldWaiting<Extract<T, RefField>>;
export const Self = Symbol("Self");
@@ -58,7 +58,8 @@ export class Doc extends RefField {
@serializable(alias("fields", map(autoObject())))
@observable
- private __fields: { [key: string]: Field | FieldWaiting | undefined } = {};
+ //{ [key: string]: Field | FieldWaiting | undefined }
+ private __fields: any = {};
private [Update] = (diff: any) => {
DocServer.UpdateField(this[Id], diff);
@@ -86,7 +87,7 @@ export namespace Doc {
return Cast(Get(doc, key, ignoreProto), ctor) as T | null | undefined;
}
export async function SetOnPrototype(doc: Doc, key: string, value: Field) {
- const proto = await Cast(doc.prototype, Doc);
+ const proto = await Cast(doc.proto, Doc);
if (proto) {
proto[key] = value;
}
@@ -97,7 +98,7 @@ export namespace Doc {
}
const delegate = new Doc();
//TODO Does this need to be doc[Self]?
- delegate.prototype = doc;
+ delegate.proto = doc;
return delegate;
}
export const Prototype = Symbol("Prototype");
diff --git a/src/new_fields/Schema.ts b/src/new_fields/Schema.ts
index 59c6db0bd..5081521c7 100644
--- a/src/new_fields/Schema.ts
+++ b/src/new_fields/Schema.ts
@@ -1,7 +1,5 @@
import { Interface, ToInterface, Cast, ToConstructor, HasTail, Head, Tail, ListSpec, ToType } from "./Types";
-import { Doc, Field, ObjectField } from "./Doc";
-import { URLField } from "./URLField";
-import { List } from "./List";
+import { Doc, Field } from "./Doc";
type AllToInterface<T extends Interface[]> = {
1: ToInterface<Head<T>> & AllToInterface<Tail<T>>,
@@ -15,7 +13,7 @@ export type Document = makeInterface<[typeof emptySchema]>;
export type makeInterface<T extends Interface[]> = Partial<AllToInterface<T>> & Doc;
// export function makeInterface<T extends Interface[], U extends Doc>(schemas: T): (doc: U) => All<T, U>;
// export function makeInterface<T extends Interface, U extends Doc>(schema: T): (doc: U) => makeInterface<T, U>;
-export function makeInterface<T extends Interface[]>(...schemas: T): (doc: Doc) => makeInterface<T> {
+export function makeInterface<T extends Interface[]>(...schemas: T): (doc?: Doc) => makeInterface<T> {
let schema: Interface = {};
for (const s of schemas) {
for (const key in s) {
@@ -35,7 +33,8 @@ export function makeInterface<T extends Interface[]>(...schemas: T): (doc: Doc)
return true;
}
});
- return function (doc: Doc) {
+ return function (doc?: Doc) {
+ doc = doc || new Doc;
if (!(doc instanceof Doc)) {
throw new Error("Currently wrapping a schema in another schema isn't supported");
}
@@ -73,8 +72,8 @@ export function makeStrictInterface<T extends Interface>(schema: T): (doc: Doc)
};
}
-export function createSchema<T extends Interface>(schema: T): T & { prototype: ToConstructor<Doc> } {
- schema.prototype = Doc;
+export function createSchema<T extends Interface>(schema: T): T & { proto: ToConstructor<Doc> } {
+ schema.proto = Doc;
return schema as any;
}
diff --git a/src/new_fields/Types.ts b/src/new_fields/Types.ts
index fbf002c84..246b0624e 100644
--- a/src/new_fields/Types.ts
+++ b/src/new_fields/Types.ts
@@ -1,4 +1,4 @@
-import { Field, Opt, FieldWaiting, FieldResult } from "./Doc";
+import { Field, Opt, FieldWaiting, FieldResult, RefField } from "./Doc";
import { List } from "./List";
export type ToType<T extends ToConstructor<Field> | ListSpec<Field>> =
@@ -18,7 +18,7 @@ export type ToConstructor<T extends Field> =
new (...args: any[]) => T;
export type ToInterface<T extends Interface> = {
- [P in keyof T]: ToType<T[P]>;
+ [P in keyof T]: FieldResult<ToType<T[P]>>;
};
// type ListSpec<T extends Field[]> = { List: ToContructor<Head<T>> | ListSpec<Tail<T>> };
@@ -37,11 +37,11 @@ export interface Interface {
// [key: string]: ToConstructor<Field> | ListSpec<Field[]>;
}
-export function Cast<T extends ToConstructor<Field> | ListSpec<Field>>(field: Field | FieldWaiting | undefined, ctor: T): FieldResult<ToType<T>>;
-export function Cast<T extends ToConstructor<Field> | ListSpec<Field>>(field: Field | FieldWaiting | undefined, ctor: T, defaultVal: ToType<T>): ToType<T>;
-export function Cast<T extends ToConstructor<Field> | ListSpec<Field>>(field: Field | FieldWaiting | undefined, ctor: T, defaultVal?: ToType<T>): FieldResult<ToType<T>> | undefined {
+export function Cast<T extends ToConstructor<Field> | ListSpec<Field>>(field: FieldResult, ctor: T): FieldResult<ToType<T>>;
+export function Cast<T extends ToConstructor<Field> | ListSpec<Field>>(field: FieldResult, ctor: T, defaultVal: ToType<T>): ToType<T>;
+export function Cast<T extends ToConstructor<Field> | ListSpec<Field>>(field: FieldResult, ctor: T, defaultVal?: ToType<T>): FieldResult<ToType<T>> | undefined {
if (field instanceof Promise) {
- return defaultVal === undefined ? field.then(f => Cast(f, ctor) as any) : defaultVal;
+ return defaultVal === undefined ? field.then(f => Cast(f, ctor) as any) as any : defaultVal;
}
if (field !== undefined && !(field instanceof Promise)) {
if (typeof ctor === "string") {