Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place.
Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place.
Path: blob/master/src/packages/util/fill/define.ts
Views: 687
/*1* This file is part of CoCalc: Copyright © 2020 Sagemath, Inc.2* License: MS-RSL – see LICENSE.md for details3*/45import { Assign, RequiredKeys } from "utility-types";6import { Optionals } from "./types";78type Requireds<T> = Pick<T, RequiredKeys<T>>;910export const required = "__!!!!!!this is a required property!!!!!!__";1112type Definition<T> = {13[K in keyof T]: {} extends Pick<T, K> ? T[K] : typeof required;14};1516/**17* `define<T, U>(props: unknown, definition)`18* Guarantees at runtime that `props` matches `definition`19* `U` must only be the optional params on `T`20*21* @return {object} T where provided defaults are guaranteed22*23* @example24*25* define<{name: string,26* highlight?: boolean,27* last?: string},28* {highlight: boolean}>(unknown_prop, {highlight: false});29*30* Unfortunately you must use both type annotations until this goes through31* https://github.com/microsoft/TypeScript/issues/2624232*33**/34export function define<T>(props: unknown, definition: Definition<T>): T;35export function define<T extends object, U extends Optionals<T>>(36props: unknown,37definition: Assign<Definition<T>, U>,38allow_extra?: boolean,39strict?: boolean40): Assign<U, Requireds<T>>;41export function define<T extends object, U extends Optionals<T>>(42props: unknown,43definition: Assign<Definition<T>, U>,44allow_extra = false,45strict = false46): Assign<U, Requireds<T>> {47// We put explicit traces before the errors in this function,48// since otherwise they can be very hard to debug.49function maybe_error(message: string): any {50const err = `${message} ${error_addendum(props, definition)}`;51if (strict) {52throw new Error(err);53} else {54console.log(err);55console.trace();56return definition as any;57}58}5960if (props == undefined) {61props = {};62}63// Undefined was checked above but TS 3.6.3 is having none of it.64// Checking here makes TS work as expected below65if (typeof props !== "object" || props == undefined) {66return maybe_error(67`BUG -- Traceback -- misc.defaults -- TypeError: function takes inputs as an object`68);69}70const result: Assign<U, Requireds<T>> = {} as any;71for (const key in definition) {72if (props.hasOwnProperty(key) && props[key] != undefined) {73if (definition[key] === required && props[key] == undefined) {74return maybe_error(75`misc.defaults -- TypeError: property '${key}' must be specified on props:`76);77}78result[key] = props[key];79} else if (definition[key] != undefined) {80if (definition[key] == required) {81maybe_error(82`misc.defaults -- TypeError: property '${key}' must be specified:`83);84} else {85result[key] = definition[key];86}87}88}8990if (!allow_extra) {91for (const key in props) {92if (!definition.hasOwnProperty(key)) {93return maybe_error(94`misc.defaults -- TypeError: got an unexpected argument '${key}'`95);96}97}98}99return result;100}101102function error_addendum(props: unknown, definition: unknown) {103try {104return `(obj1=${exports.trunc(105exports.to_json(props),1061024107)}, obj2=${exports.trunc(exports.to_json(definition), 1024)})`;108} catch (err) {109return "";110}111}112113114