Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 9 additions & 2 deletions src/staged-query/schema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,15 +49,22 @@ interface IoTsValidation {
readonly _tag: "Left" | "Right";
}

interface IoTsCodec<A = unknown, O = unknown, I = unknown> {
/**
* The shape of an io-ts codec that a schema field accepts
*
* Declared as a type alias so TypeScript gives it an implicit string index
* signature: `Object.entries` on a codec lists its own enumerable properties
* as `[string, unknown]`, where an interface would make them `any`.
*/
type IoTsCodec<A = unknown, O = unknown, I = unknown> = {
readonly _A: A;
readonly _O: O;
readonly _I: I;
readonly name: string;
is(u: A | I): boolean;
encode(a: A): O;
decode(i: I): IoTsValidation;
}
};

export type FieldType = StringFieldType | IoTsCodec;

Expand Down
34 changes: 34 additions & 0 deletions src/tests/field_type.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import { expect } from "chai";
import type { FieldType, StringFieldType } from "../schema";
import type { Same } from "./helpers/same-type";

type IsAny<T> = 0 extends 1 & T ? true : false;

type Codec = Exclude<FieldType, StringFieldType>;

function propertiesOf(codec: Codec) {
return Object.entries(codec);
}

type PropertyValue = ReturnType<typeof propertiesOf>[number][1];

const valuesAreNotAny: Same<IsAny<PropertyValue>, false> = true;
const valuesAreUnknown: Same<PropertyValue, unknown> = true;

describe("Field types", () => {
it("Types the own properties of a codec as unknown values", () => {
const codec: Codec = {
_A: 0,
_O: 0,
_I: 0,
name: "number",
is: (u): boolean => u === 0,
encode: (a) => a,
decode: () => ({ _tag: "Right" }),
};
const names = propertiesOf(codec).map(([name]) => name);
expect(names).to.include.members(["name", "is", "encode", "decode"]);
expect(valuesAreNotAny).to.equal(true);
expect(valuesAreUnknown).to.equal(true);
});
});
Loading