Question
How can I define a record type Shape<RootType>
whose values (if specified) can only be "A" if the key can index RootType
and either "B" or "C" otherwise?
Test cases
type User = {
id: number;
name: string;
unused: number;
}
declare function test<T extends Shape<User>>(): void;
// The following should compile:
test<{
id: "A",
name: "A",
something: "B",
else: "C",
}>();
// The followings shouldn't compile:
test<{ id: "B" }>(); // `id` should only be "A"
test<{ name: 123 }>(); // `name` should only be "A"
test<{ something: "A" }>(); // extra keys can only be "B" or "C"
What have I tried?
type Shape<RootType> = {
[KeyType in symbol]?:
KeyType extends RootType
? "A"
: "B" | "C"
}
I've tried the above but that type seems to extend whatever record type.
CodePudding user response:
You would have to map over the keys of T
and check for each key K
if it extends keyof RootType
. To make T
available in Shape
, we need to pass it to Shape
as a generic parameter too.
declare function test<T extends Shape<User, T>>(): void;
type Shape<RootType, T> = {
[K in keyof T]:
K extends keyof RootType
? "A"
: "B" | "C"
}
// The following is valid:
test<{
id: "A",
name: "A",
something: "B",
else: "C",
}>();
// The followings aren't valid:
test<{ id: "B" }>(); // `id` should only be "A"
test<{ name: 123 }>(); // `name` should only be "A"
test<{ something: "A" }>(); // extra keys can only be "B" or "C"