How to use the tiny-decoders.record 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
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),
      };
github lydell / tiny-decoders / typescript / type-annotations.ts View on Github external
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),
    // $ExpectError
    extra: field("extra", string),
    // ^^^^^^^^^^^^^^^^^^^^^^^^^^
    // Type '{ name: string; age: number; extra: string; }' is not assignable to type 'Person'.
    //   Object literal may only specify known properties, and 'extra' does not exist in type 'Person'. ts(2322)
  })
);
greet(personDecoder8(testPerson));
// See these TypeScript issues for more information:
// https://github.com/microsoft/TypeScript/issues/7547
// https://github.com/microsoft/TypeScript/issues/18020

/*
github lydell / tiny-decoders / typescript / type-annotations.ts View on Github external
//     }
  //
  // Those extra fields are just noisy. They exist because of this:
  // https://github.com/microsoft/TypeScript/pull/19513
  //
  // But can we get rid of them?
}

// Turns out we can get rid of the extra properties by using the good old
// `identity` function! It’s just a function that returns whatever is passed to
// it. A bit of an ugly workaround, but it works.
const id = (x: T): T => x;

// And when wrapping each `return` in `id(...)` the extra properties vanish!
// $ExpectType Decoder<{ type: "anonymous"; sessionId: number; } | { type: "registered"; id: number; name: string; }>
const userDecoder5 = record((field, fieldError) => {
  const type = field("type", string);

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

    case "registered":
      return id({
        type: "registered" as const,
        id: field("id", number),
        name: field("name", string),
      });
github lydell / tiny-decoders / typescript / user.ts View on Github external
active: boolean,
    id: either(string, number),
  })
);
verifyUser(
  record(field => ({
    extra: field("extra", string),
    extra2: field("extra2", () => undefined),
    name: field("name", string),
    age: field("age", number),
    active: field("active", boolean),
    id: field("id", either(string, number)),
  }))
);
verifyUser(
  record(field => ({
    extra: field("extra", string),
    extra2: field("extra2", () => undefined),
    name: field("name", string),
    age: field("age", number),
    active: field("active", boolean),
    id: field("id", either(string, number)),
  }))
);

// Misspelled field ("naem" instead of "name"):
verifyUser(
  // $ExpectError
  autoRecord({
    naem: string,
    age: number,
    active: boolean,
github lydell / tiny-decoders / typescript / type-annotations.ts View on Github external
}));
// $ExpectError
const personDecoder2Auto: Decoder = autoRecord({
  //  ^^^^^^^^^^^^^^^^^^
  // Type 'Decoder<{ name: string; aye: number; }>' is not assignable to type 'Decoder'.
  //   Property 'age' is missing in type '{ name: string; aye: number; }' but required in type 'Person'. ts(2322)
  name: string,
  aye: number,
});
greet(personDecoder2(testPerson));
greet(personDecoder2Auto(testPerson));

// Here’s a shorter way of writing the above – which also gives better error
// messages!
// $ExpectError
const personDecoder3 = record(field => ({
  name: field("name", string),
  aye: field("age", number),
}));
// ^
// Property 'age' is missing in type '{ name: string; aye: number; }' but required in type 'Person'.ts(2741)
const personDecoder3Auto = autoRecord({
  name: string,
  // $ExpectError
  aye: number,
  // ^^^^^^^^
  // Argument of type '{ name: (value: unknown) => string; aye: (value: unknown) => number; }' is not assignable to parameter of type '{ name: Decoder; age: Decoder; }'.
  //   Object literal may only specify known properties, and 'aye' does not exist in type '{ name: Decoder; age: Decoder; }'. ts(2345)
});
greet(personDecoder3(testPerson));
greet(personDecoder3Auto(testPerson));
github lydell / tiny-decoders / typescript / type-annotations.ts View on Github external
type: constant("registered"),
        id: number,
        name: string,
      });

    default:
      throw new TypeError(`Unknown user type: ${repr(type)}`);
  }
}

// This “decodes” the "type" field using `getUserDecoder`. Remember that a
// decoder is allowed to return whatever it wants. `getUserDecoder` returns a
// _new_ decoder, which we immediately call. I haven’t found a nicer way to do
// this so far.
// $ExpectType Decoder<{ type: "anonymous"; sessionId: number; } | { type: "registered"; id: number; name: string; }>
const userDecoder6 = record((field, _fieldError, obj, errors) =>
  field("type", getUserDecoder)(obj, errors)
);

// Finally, there’s one last little detail to know about: How optional fields
// are inferred.
// $ExpectType Decoder<{ title: string; description: string | undefined; }>
const itemDecoder = autoRecord({
  title: string,
  description: optional(string),
});

// As you can see above, fields using the `optional` decoder are always inferred
// as `key: T | undefined`, and never as `key?: T`. This means that you always
// have to specify the optional fields:
type Item = ReturnType;
// $ExpectError
github lydell / tiny-decoders / typescript / user.ts View on Github external
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);

// `id: string` also satisfies `string | number`.
verifyUser(
  autoRecord({
    id: string,
    name: string,
    age: number,
    active: boolean,
  })
github lydell / LinkHints / src / shared / options.js View on Github external
export function makeOptionsDecoder(defaults: Options): Decoder {
  return record(field => ({
    chars: field("chars", map(string, validateChars), {
      default: defaults.chars,
    }),
    autoActivate: field("autoActivate", boolean, {
      default: defaults.autoActivate,
    }),
    overTypingDuration: field("overTypingDuration", decodeUnsignedInt, {
      default: defaults.overTypingDuration,
    }),
    css: field("css", string, {
      default: defaults.css,
    }),
    logLevel: field("logLevel", map(string, decodeLogLevel), {
      default: defaults.logLevel,
    }),
    useKeyTranslations: field("useKeyTranslations", boolean, {
github lydell / LinkHints / src / worker / decoders.js View on Github external
import { type Box, decodeUnsignedFloat } from "../shared/main";

export type FrameMessage =
  | {
      type: "FindElements",
      token: string,
      types: ElementTypes,
      viewports: Array,
    }
  | {
      type: "UpdateElements",
      token: string,
      viewports: Array,
    };

export const decodeFrameMessage: Decoder = record(
  (field, fieldError) => {
    const type = field("type", string);

    switch (type) {
      case "FindElements":
        return {
          type: "FindElements",
          token: "",
          types: field("types", decodeElementTypes),
          viewports: field("viewports", decodeViewports),
        };

      case "UpdateElements":
        return {
          type: "UpdateElements",
          token: "",