Types
KeyOf
Use ft.KeyOf to validate an unknown value is a key of a given object.
String Keys
import * as ft from "funtypes";
export const UserKeySchema = ft.KeyOf({
id: {},
name: {},
})
// => ft.Codec<"id" | "name">
export type UserKey = ft.Static<typeof UserKeySchema>;
// => "id" | "name"
// β
Valid key
assert.deepEqual(UserKeySchema.parse("name"), "name");
// π¨ Invalid key
assert.throws(() => UserKeySchema.parse("other_string"));
// π¨ Totally different type
assert.throws(() => UserKeySchema.parse([42]));
Numeric Keys
If the type has numeric keys, we allow both the number and the string as valid values.
export const MyKeySchema = ft.KeyOf({
42: {},
five: {},
})
// => ft.Codec<42 | "42" | "five">
export type MyKey = ft.Static<typeof MyKeySchema>;
// => 42 | "42" | "five"
// β
Valid number key
assert.deepEqual(UserKeySchema.parse(42), 42);
// β
Valid number key represented as a string
assert.deepEqual(UserKeySchema.parse("42"), "42");
// β
Valid string key
assert.deepEqual(UserKeySchema.parse("five"), "five");
// π¨ Invalid number key
assert.throws(() => UserKeySchema.parse(1));
// π¨ Invalid string key
assert.throws(() => UserKeySchema.parse("other_string"));
// π¨ Totally different type
assert.throws(() => UserKeySchema.parse([42]));
TypeScript is weird about numeric keys sometimes
TypeScript gives a different type to { "42": {} } vs. { 42: {} } but they have the same type at runtime, so we can't tell them apart. Because of this, we'll allow both the numeric representation and the string representation at runtime, but if you use { "42": {} }, the static types will incorrectly only include the string representation.
export const MyKeySchema = ft.KeyOf({ "42": {} })
// => ft.Codec<"42">
// The types would suggest that this should throw,
// but it does not.
assert.deepEqual(
MyKeySchema.parse(42),
42,
);