TypeScript keyof typeof for type generation

eye-catchJavaScript/TypeScript
Sponsored links
Sponsored links

Keyof

keyof extracts property list of the target type or interface.

interface Book {
    name: string;
    authorName: string;
    price: number;
    publishedDate: Date;
}

// BookKey = "name" | "authorName" | "price" | "publishedDate"
type BookKey = keyof Book;

This can be used when you want to create a function that sorts a book list. In this case, the function wants to accept one of the keys of Book type.

function sortBooks(books: Book[], key: BookKey) {
    // key is "name" | "authorName" | "price" | "publishedDate"
}
Sponsored links

Typeof

typeof generates a type from an actual object.

const person = {
    name: "Yuto",
    age: 35,
};

// {
//     name: string;
//     age: number;
// }
type PersonType = typeof person;

// error
const person1: typeof person = { name: "error", agge: 32 };

// not error
const person2: typeof person = { name: "OK", age: 32 };

// error because type is different
person2.age = "44";

You can extract the value list from an array to generate a type.

const LogLevelArray = [
    "Trace",
    "Debug",
    "Info",
    "Warn",
    "Error",
] as const;

// "Trace" | "Debug" | "Info" | "Warn" | "Error"
type LogType = typeof LogLevelArray[number];

Combination of keyof and typeof

keyof and typeof can be used on the same line.

Extract enum Key value list to use for a type

It can extract the keys from an enum.

enum LogLevel {
    Trace = "AA",
    Debug = "BB",
    Info = "CC",
    Warn = "DD",
    Error = "EE",
}
// "Trace" | "Debug" | "Info" | "Warn" | "Error"
type LogLevelKey = keyof typeof LogLevel;

typeof LogLevel convert the enum to an object. The properties of the object are Trace, Debug, Info, and so on. Therefore, the properties are extracted.

You might think you can achieve the same thing by using keyof in the following way.

//  number | typeof Symbol.iterator | "toString" | "charAt" | "charCodeAt" |
//  "concat" | "indexOf" | "lastIndexOf" | "localeCompare" | "match" | "replace" |
//  "search" | "slice" | ... 34 more ... | "trimRight"
type LogLevelKey2 = keyof LogLevel;

But as you can see, the result is completely different because it extracts the properties against the enum object.

Extract key list or value list from a const object

Some people prefer const object over enum because enum is not supported by JavaScript. In this case, we need to define the value type in order to restrict accepted values. Then, this keyof typeof is useful.

const LogLevelObj = {
    Trace: 10,
    Debug: 20,
    Info: 30,
    Warn: 40,
    Error: 50,
} as const;

// {
//     readonly Trace: 10;
//     readonly Debug: 20;
//     readonly Info: 30;
//     readonly Warn: 40;
//     readonly Error: 50;
// }
type LogTypeObjType = typeof LogLevelObj;

// "Trace" | "Debug" | "Info" | "Warn" | "Error"
type LogTypeKey = keyof LogTypeObjType;

// 10 | 20 | 30 | 40 | 50
type LogTypeValue = typeof LogLevelObj[LogTypeKey];

If you don’t need the key type, you can also implement it in the following way.

type LogTypeValue = typeof LogLevelObj[keyof typeof LogLevelObj];

LogTypeKey is just inlined.

Related Article

keyof typeof is used in the following article to write a better switch-case.

Comments

Copied title and URL