How to use the tiny-decoders.autoRecord function in tiny-decoders

To help you get started, we’ve selected a few tiny-decoders examples, based on popular ways it is used in public projects.

Secure your code as it's written. Use Snyk Code to scan source code in minutes - no build needed - and fix issues immediately.

github lydell / tiny-decoders / typescript / type-annotations.ts View on Github external
return `${personA.name} meets ${personB.name}`;
}
meet(personDecoder9(testPerson), personDecoder9Auto(testPerson));

// If it feels like you are specifying everything twice – once in a `type` or
// `interface`, and once in the decoder – you might find this `ReturnType`
// technique interesting. If annotating your decoders like shown earlier in this
// file (`record((field): MyType => ({...}))` and `autoRecord({...})`),
// TypeScript will make sure that your type definition and decoders stay in
// sync, so there’s little room for error there. But with the `ReturnType`
// approach you don’t have to write what your records look like “twice.”
// Personally I don’t mind the “duplication,” but if you do – try out the
// `ReturnType` approach!

// Here’s a more complex example for trying out TypeScript’s inference.
const userDecoder = autoRecord({
  id: either(string, number),
  name: string,
  age: number,
  active: boolean,
  country: optional(string),
  type: constant("user"),
});

// Let TypeScript infer the `User` type:
type User = ReturnType;
// Try hovering over `User` in the line above – your editor should reveal the
// exact shape of the type.

const data = {
  id: 1,
  name: "John Doe",
github lydell / LinkHints / src / shared / keyboard.js View on Github external
ctrl: boolean,
  // If missing it means that the shift key doesn’t matter. For example, it
  // doesn’t matter if you need to press shift to type a `/` or not (which
  // differs between keyboard layouts).
  shift: ?boolean,
};

export type Shortcut = {
  key: string,
  alt: boolean,
  cmd: boolean,
  ctrl: boolean,
  shift: boolean,
};

const decodeShortcut: Decoder = autoRecord({
  key: string,
  alt: boolean,
  cmd: boolean,
  ctrl: boolean,
  shift: boolean,
});

const EMPTY_SHORTCUT: Shortcut = {
  key: "",
  alt: false,
  cmd: false,
  ctrl: false,
  shift: false,
};

function requireModifier(shortcut: Shortcut): Shortcut {
github lydell / tiny-decoders / typescript / rename.ts View on Github external
import { Decoder, autoRecord, map, number, string } from "tiny-decoders";

interface Camel {
  firstName: string;
  age: number;
}

const verifyCamel = (decoder: Decoder): Camel => decoder(undefined);

// Successful rename (approach 1):
verifyCamel(
  map(
    autoRecord({
      first_name: string,
      age: number,
    }),
    ({ first_name: firstName, ...rest }) => ({ firstName, ...rest })
  )
);

// Didn’t remove "first_name":
// Unlike Flow, TypeScript does not have exact types. Returning an object with
// extraneous properties is OK.
verifyCamel(
  map(
    autoRecord({
      first_name: string,
      age: number,
    }),
github lydell / tiny-decoders / typescript / type-annotations.ts View on Github external
// https://github.com/microsoft/TypeScript/issues/18020

/*
 * MAKING A TYPE FROM THE DECODER
 */

// Rather than first typing out an `interface` for `Person` and then essentially
// typing the same thing again in the decoder (especially `autoRecord` decoders
// look almost identical to `interface` they decode to!), you can start with the
// decoder and extract the type afterwards with TypeScript’s `ReturnType`
// utility.
const personDecoder9 = record(field => ({
  name: field("name", string),
  age: field("age", number),
}));
const personDecoder9Auto = autoRecord({
  name: string,
  age: number,
});
// $ExpectType { name: string; age: number; }
type Person2 = ReturnType;
// $ExpectType { name: string; age: number; }
type Person3 = ReturnType;
greet(personDecoder9(testPerson));
greet(personDecoder9Auto(testPerson));
function meet(personA: Person2, personB: Person3): string {
  return `${personA.name} meets ${personB.name}`;
}
meet(personDecoder9(testPerson), personDecoder9Auto(testPerson));

// If it feels like you are specifying everything twice – once in a `type` or
// `interface`, and once in the decoder – you might find this `ReturnType`
github lydell / tiny-decoders / typescript / type-annotations.ts View on Github external
}));
const personDecoder6Auto: Decoder = autoRecord({
  name: string,
  age: number,
  extra: string,
});
greet(personDecoder6(testPerson));
greet(personDecoder6Auto(testPerson));

// The shorter notation does produce an error for `autoRecord`, but not for `record`.
const personDecoder7 = record(field => ({
  name: field("name", string),
  age: field("age", number),
  extra: field("extra", string),
}));
const personDecoder7Auto = autoRecord({
  name: string,
  age: number,
  // $ExpectError
  extra: string,
  // ^^^^^^^^^^
  // Argument of type '{ name: (value: unknown) => string; age: (value: unknown) => number; extra: (value: unknown) => string; }' is not assignable to parameter of type '{ name: Decoder; age: Decoder; }'.
  //   Object literal may only specify known properties, and 'extra' does not exist in type '{ name: Decoder; age: Decoder; }'. ts(2345)
});
greet(personDecoder7(testPerson));
greet(personDecoder7Auto(testPerson));

// Luckily, the last type annotation style for `record` does produce an error!
const personDecoder8 = record(
  (field): Person => ({
    name: field("name", string),
    age: field("age", number),
github lydell / tiny-decoders / typescript / type-annotations.ts View on Github external
//   Object literal may only specify known properties, and 'aye' does not exist in type 'Person'. ts(2322)
  })
);
greet(personDecoder4(testPerson));

/*
 * EXTRA PROPERTY
 */

// TypeScript allows passing extra properties, so without type annotations there are no errors:
const personDecoder5 = record(field => ({
  name: field("name", string),
  age: field("age", number),
  extra: field("extra", string),
}));
const personDecoder5Auto = autoRecord({
  name: string,
  age: number,
  extra: string,
});
greet(personDecoder5(testPerson));
greet(personDecoder5Auto(testPerson));

// Adding `Decoder` does not seem to help TypeScript find any errors:
const personDecoder6: Decoder = record(field => ({
  name: field("name", string),
  age: field("age", number),
  extra: field("extra", string),
}));
const personDecoder6Auto: Decoder = autoRecord({
  name: string,
  age: number,
github lydell / tiny-decoders / typescript / user.ts View on Github external
optional,
  record,
  string,
} from "tiny-decoders";

interface User {
  name: string;
  age: number;
  active: boolean;
  id: string | number;
}

const verifyUser = (decoder: (value: unknown) => User): User =>
  decoder(undefined);

const userDecoder: (value: unknown) => User = autoRecord({
  name: string,
  age: number,
  active: boolean,
  id: either(string, number),
});

verifyUser(userDecoder);

const userDecoder2: (value: unknown) => User = record(field => ({
  name: field("name", string),
  age: field("age", number),
  active: field("active", boolean),
  id: field("id", either(string, number)),
}));

verifyUser(userDecoder2);
github lydell / LinkHints / src / shared / keyboard.js View on Github external
: shortcut,
    { ...EMPTY_SHORTCUT }
  );
}

export type KeyboardMapping = {
  shortcut: Shortcut,
  action: KeyboardAction,
};

export const decodeKeyboardMapping: Decoder = autoRecord({
  shortcut: decodeShortcut,
  action: map(string, decodeKeyboardAction),
});

export const decodeKeyboardMappingWithModifiers: Decoder = autoRecord(
  {
    shortcut: map(decodeShortcut, requireModifier),
    action: map(string, decodeKeyboardAction),
  }
);

export type KeyboardModeBackground =
  | { type: "FromHintsState" }
  | { type: "PreventOverTyping", sinceTimestamp: number }
  | { type: "Capture" };

export type KeyboardModeWorker =
  | "Normal"
  | "Hints"
  | "PreventOverTyping"
  | "Capture";
github lydell / LinkHints / src / shared / perf.js View on Github external
numVisibleElements: number,
  numVisibleFrames: number,
  bailed: number,
  durations: decodeDurations,
});

export type Perf = Array<{
  timeToFirstPaint: number,
  timeToLastPaint: number,
  topDurations: Durations,
  collectStats: Array,
  renderDurations: Durations,
}>;

export const decodePerf: Decoder = array(
  autoRecord({
    timeToFirstPaint: number,
    timeToLastPaint: number,
    topDurations: decodeDurations,
    collectStats: array(decodeStats),
    renderDurations: decodeDurations,
  })
);

export type TabsPerf = { [tabId: string]: Perf, ... };

export const decodeTabsPerf: Decoder = dict(decodePerf);

export class TimeTracker {
  _durations: Durations = [];
  _current: ?{ label: string, timestamp: number } = undefined;
github lydell / LinkHints / src / options / Program.js View on Github external
return;
      }
      this.hasRestoredPosition = true;
      const recordProps = {
        expandedPerfTabIds: optional(
          map(array(string), ids =>
            ids.filter(id => ({}.hasOwnProperty.call(this.state.perf, id)))
          ),
          ([]: Array)
        ),
        expandedPerf: optional(boolean, false),
        expandedDebug: optional(boolean, false),
        scrollY: optional(number, 0),
      };
      const data = await browser.storage.local.get(Object.keys(recordProps));
      const decoder = autoRecord(recordProps);
      const { scrollY, expandedPerfTabIds, ...state } = decoder(data);
      this.setState({ ...state, expandedPerfTabIds }, () => {
        window.scrollTo(0, scrollY);
      });
    }
  }