'Getting type of a property of a typescript class using keyof operator

As stated in the documentation of Typescript about the keyof operator, one can get a property of an object instance using the function below.

function getProperty<T, K extends keyof T>(o: T, name: K) {
    return o[name];
}

Of course, one can get the type of the property by replacing return o[name] into return typeof o[name]. Is there a way to retrieve the type of the property without passing any object instance?

function getPropertyType<T>(name: keyof T) {
    // something like T[name]?
}


Solution 1:[1]

Yes, lookup types work just fine:

type BarType = FooType['bar'];

It expects in this case that FooType is an object like:

type FooType = {
    bar: string;
}

It sets BarType to the same type as FooType['bar'], so to a string.

PS: FooType can also be an interface or class.

Solution 2:[2]

Of course, one can get the type of the property by replacing return o[name] into return typeof o[name].

Not really... if you did that:

function getTypeofProperty<T, K extends keyof T>(o: T, name: K) {
    return typeof o[name];
}

You would get a return value of the type "string" | "number" | "boolean" | "symbol" | "undefined" | "object" | "function", because you're using the JavaScript typeof operator at runtime, which returns a string like "object", not the compile-time type seen by TypeScript.

TypeScript also uses the keyword typeof as the compile-time type query operator. You can tell the difference by looking at the places where it appears. The type query typeof only appears in places where you are writing a type. For example:

const a = { foo: 0 };
const b: Array<typeof a> = [{ foo: 1 }, { foo: 2 }, {foo: 3}]; 
const c: string = typeof a; // "object"

In b, you can see that typeof a appears where you would write a type expression, so it is a TypeScript type query, and Array<typeof a> is evaluated as Array<{foo: number}>. On the other hand, in c, typeof a appears where you would write an value expression, so it is the JavaScript typeof operator, and will evaluate to the string "object" at runtime.


As @k0pernikus mentioned, TypeScript doesn't (and doesn't intend to) allow you to get compile-time type information at runtime. So there is no typeof operator which acts at runtime and returns compile-time information.


Of course, if you want type information about a property at compile time, you can do that, using what's called lookup types. Let's examine the return value of that getProperty() function:

function getProperty<T, K extends keyof T>(o: T, name: K) {
    return  o[name];
} // hover over getProperty to see that the return value is of type T[K]

That T[K] in a type position means "the type of property with a key of type K on an object of type T". Since this is a type-level operation, you can do it at compile-time without declaring any values of the type T or K. For example,

type RegExpFlags = RegExp['flags']; // RegExpFlags is string
const flags: RegExpFlags = 'ig';

Here, you are looking up the "flags" key of the type of RegExp objects and getting back the string type, and you can declare a value of type RegExp['flags'] without having a value of type RegExp anywhere.


That's the closest I can come to answering your question without more information about what you need. Hope that helps. Good luck!

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1
Solution 2 jcalz