17

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...

3

3 Answers 3

12

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

Sign up to request clarification or add additional context in comments.

2 Comments

This is O(n!), tread with caution.
Any way around this? - Type instantiation is excessively deep and possibly infinite. ts(2589)
5

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")[]

Comments

4

You can use keyof type operator.

export type UsersSchema = {
  id: number;
  firstName: string;
  lastName: string;
  email: string;
};

type Keys = keyof UsersSchema // "id" | "firstName" | "lastName" | "email"

4 Comments

Is there a way to use them as value now? fetch("https://my-url?filter=id,firstName,lastName,email")?
@MatthisKohli As far as i know, it's impossible to use type as a value. However, you can use this key type to create type-checking functions
I'm not getting any errors on the type line but I can't write this out to the console, console.log("My keys", Keys) 'Keys' only refers to a type, but is being used as a value here.ts(2693). I also tried assigning to a variable and that errored.
so what do I do with this Keys now? How does this answer a question?

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.