Lets say we have this Type:
export type UsersSchema = {
id: number;
firstName: string;
lastName: string;
email: string;
};
Is there a way to make this pseudo-code work:
Object.keys(UsersSchema) which would ideally yield: ['id', 'firstName', 'lastNight', 'email']
Obviously UsersSchema is not a value, so the above does not work...
The type doesn't exist at run time.
However, (leaning heavily on this beautiful answer, which will require TS4.x because of its use of recursive conditional types), you can create a tuple type that enforces a tuple with the required names.
So:
type TupleUnion<U extends string, R extends string[] = []> = {
[S in U]: Exclude<U, S> extends never
? [...R, S]
: TupleUnion<Exclude<U, S>, [...R, S]>;
}[U] & string[];
export type UsersSchema = {
id: number;
firstName: string;
lastName: string;
email: string;
};
const allKeysOfUsersSchema: TupleUnion<keyof UsersSchema> =
["id", "firstName", "lastName", "email"]; //OK
const wrongKeysOfUsersSchema: TupleUnion<keyof UsersSchema> =
["monkey", "firstName", "lastName", "email"]; //error
const missingKeysOfUsersSchema: TupleUnion<keyof UsersSchema> =
["id", "firstName", "lastName"]; //error
const tooManyKeysOfUsersSchema: TupleUnion<keyof UsersSchema> =
["id", "firstName", "lastName", "email", "cat"]; //error
OK... so you'll have to maintain this separate tuple, manually, but at least if things change, the compiler will push you into remedial action, so type-safety is maintained.
Playground link
in addition to hwasurr answer you probably need to put the keys in parenthesis to get the right type
the array of keys:
type Keys = (keyof UsersSchema)[]
// ("id" | "firstName" | "lastName" | "email")[]
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With