Secure your code as it's written. Use Snyk Code to scan source code in minutes - no build needed - and fix issues immediately.
}
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",
age: 30,
// $ExpectType { a: string; b: number; c: boolean | undefined; }
autoRecord({ a: string, b: number, c: optional(boolean) })(undefined);
// $ExpectType string
deep([], string)(undefined);
// $ExpectType string | undefined
optional(string)(undefined);
// $ExpectType string
optional(string, "default")(undefined);
// $ExpectType string | null
optional(string, null)(undefined);
// $ExpectType string
map(string, string)(undefined);
// $ExpectType string | number
either(string, number)(undefined);
// $ExpectType string | number | boolean | { readonly [key: string]: unknown; }
either(either(boolean, string), either(number, mixedDict))(undefined);
// $ExpectType string
lazy(() => string)(undefined);
// $ExpectError
boolean(undefined, []);
// $ExpectError
number(undefined, []);
// $ExpectError
string(undefined, []);
// $ExpectError
mixedArray(undefined, []);
// $ExpectError
mixedDict(undefined, []);
// $ExpectError
constant("const")(undefined, []);
// $ExpectError
age: field("age", number),
active: field("active", boolean),
id: field("id", either(string, number)),
})
)
);
// Extra fields:
verifyUser(
autoRecord({
extra: string,
extra2: () => undefined,
name: string,
age: number,
active: boolean,
id: either(string, number),
})
);
verifyUser(
autoRecord({
// $ExpectError
extra: string,
extra2: () => undefined,
name: string,
age: number,
active: boolean,
id: either(string, number),
})
);
verifyUser(
record(field => ({
extra: field("extra", string),
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);
// `id: string` also satisfies `string | number`.
verifyUser(
autoRecord({
record(field => ({
naem: field("naem", string),
age: field("age", number),
active: field("active", boolean),
id: field("id", either(string, number)),
}))
);
// Wrong type for "name":
verifyUser(
// $ExpectError
autoRecord({
name: number,
age: number,
active: boolean,
id: either(string, number),
})
);
verifyUser(
// $ExpectError
record(field => ({
name: field("name", number),
age: field("age", number),
active: field("active", boolean),
id: field("id", either(string, number)),
}))
);
// "name" isn’t optional:
verifyUser(
// $ExpectError
autoRecord({
triple(string, boolean, boolean)(undefined, []);
// $ExpectError
triple(string, boolean, boolean)(undefined, {});
autoRecord({})(undefined, []);
// $ExpectError
autoRecord({})(undefined, {});
deep([], string)(undefined, []);
// $ExpectError
deep({}, string)(undefined, []);
optional(string)(undefined, []);
// $ExpectError
optional(string)(undefined, {});
map(string, string)(undefined, []);
// $ExpectError
map(string, string)(undefined, {});
either(string, number)(undefined, []);
// $ExpectError
either(string, number)(undefined, {});
lazy(() => string)(undefined, []);
// $ExpectError
lazy(() => string)(undefined, {});
constant(undefined);
constant(null);
constant(true);
constant(false);
constant(0);
constant("");
// Arrays can’t be compared easily:
// $ExpectError
constant([]);
// Objects can’t be compared easily:
const userDecoder2 = record(field => ({
id: field("id", either(string, number)),
name: field("name", string),
age: field("age", number),
active: field("active", boolean),
country: field("country", optional(string)),
type: field("type", constant("user")),
}));
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)),
}))
);
record(field => ({
name: field("name", number),
age: field("age", number),
active: field("active", boolean),
id: field("id", either(string, number)),
}))
);
return type;
default:
throw new TypeError(`Invalid ElementType: ${repr(type)}`);
}
}
export function decodeElementTypesConstants(type: string): ElementTypes {
switch (type) {
case "selectable":
return type;
default:
throw new TypeError(`Invalid ElementTypes constant: ${repr(type)}`);
}
}
export const decodeElementTypes: Decoder = either(
map(string, decodeElementTypesConstants),
array(map(string, decodeElementType))
);
export type Point = {
x: number,
y: number,
align: "left" | "right",
debug: string,
};
export type HintMeasurements = {
...Point,
maxX: number,
weight: number,
};