How to use tiny-decoders - 10 common examples

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 / LinkHints / src / worker / decoders.js View on Github external
};

      case "UpdateElements":
        return {
          type: "UpdateElements",
          token: "",
          viewports: field("viewports", decodeViewports),
        };

      default:
        throw fieldError("type", `Unknown FrameMessage type: ${repr(type)}`);
    }
  }
);

const decodeViewports: Decoder> = array(
  autoRecord({
    // A viewport of a frame can be partially off-screen.
    x: number,
    y: number,
    width: decodeUnsignedFloat,
    height: decodeUnsignedFloat,
  })
);
github lydell / tiny-decoders / typescript / decoders.ts View on Github external
// $ExpectType { readonly [key: string]: unknown; }
mixedDict(undefined);
// $ExpectType true
constant(true)(undefined);
// $ExpectType false
constant(false)(undefined);
// $ExpectType 0
constant(0)(undefined);
// $ExpectType "const"
constant("const")(undefined);
// $ExpectType undefined
constant(undefined)(undefined);
// $ExpectType null
constant(null)(undefined);
// $ExpectType string[]
array(string)(undefined);
// $ExpectType { [key: string]: string; }
dict(string)(undefined);
// $ExpectType string
record(() => "")(undefined);
// $ExpectType { a: string; }
record(field => ({ a: field("a", string) }))(undefined);
// $ExpectType string
tuple(() => "")(undefined);
// $ExpectType string[]
tuple(item => [item(0, string)])(undefined);
// $ExpectType [string]
tuple<[string]>(item => [item(0, string)])(undefined);
// $ExpectType [string, boolean]
pair(string, boolean)(undefined);
// $ExpectType [string, boolean, boolean]
triple(string, boolean, boolean)(undefined);
github lydell / tiny-decoders / typescript / type-annotations.ts View on Github external
name: field("name", string),
    // $ExpectError
    aye: field("age", number),
    // ^^^^^^^^^^^^^^^^^^^^^^
    // Type '{ name: string; aye: number; }' is not assignable to type 'Person'.
    //   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),
github lydell / tiny-decoders / typescript / type-annotations.ts View on Github external
active: true,
  country: undefined,
  // $ExpectError
  type: "nope",
  // ^^^^^^^^^
  // Type '"nope"' is not assignable to type '"user"'. ts(2322)
};

/*
 * MAKING A TYPE FROM THE DECODER – CAVEATS
 */

// Let’s say we need to support two types of users – anonymous and registered ones.
// Unfortunately, TypeScript doesn’t infer the type you might have expected:
// $ExpectType Decoder<{ type: string; sessionId: number; id?: undefined; name?: undefined; } | { type: string; id: number; name: string; sessionId?: undefined; }>
const userDecoder3 = record((field, fieldError) => {
  const type = field("type", string);

  switch (type) {
    case "anonymous":
      return {
        type: "anonymous",
        sessionId: field("sessionId", number),
      };

    case "registered":
      return {
        type: "registered",
        id: field("id", number),
        name: field("name", string),
      };