使用keyof运算符获取typescript类的属性类型

bmd*_*ruz 7 typescript

作为打字稿的有关文件中规定keyof操作,可以使用下面的函数得到一个对象实例的属性.

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

当然,可以通过更换得到属性的类型return o[name]return typeof o[name].有没有办法在不传递任何对象实例的情况下检索属性的类型?

function getPropertyType<T>(name: keyof T) {
    // something like T[name]?
}
Run Code Online (Sandbox Code Playgroud)

flo*_*ori 29

是的,查找类型应该可以正常工作。喜欢:

type FooType = { // interfaces or classes of course also possible
    bar: string;
}

type BarType = FooType['bar']; // BarType is a string now
Run Code Online (Sandbox Code Playgroud)

  • 如果您因为 `FooType` 可能为 null 或未定义而遇到麻烦,请使用 [`NonNullable`](https://www.typescriptlang.org/docs/handbook/utility-types.html#nonnullabletype)。`类型 BarType = NonNullable&lt;FooType&gt;['bar']` (4认同)

jca*_*alz 11

当然,可以通过更换得到属性的类型return o[name]return typeof o[name].

不是......如果你那样做:

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

您将获得该类型的返回值"string" | "number" | "boolean" | "symbol" | "undefined" | "object" | "function",因为您在运行时使用JavaScript typeof运算符,它返回一个字符串,而不是TypeScript看到的编译时类型."object"

TypeScript还使用关键字typeof作为编译时类型查询运算符.您可以通过查看它出现的位置来区分它们.类型查询typeof仅出现在您正在编写类型的位置.例如:

const a = { foo: 0 };
const b: Array<typeof a> = [{ foo: 1 }, { foo: 2 }, {foo: 3}]; 
const c: string = typeof a; // "object"
Run Code Online (Sandbox Code Playgroud)

b,您可以看到typeof a出现在您编写类型表达式的位置,因此它是TypeScript类型查询,并被Array<typeof a>评估为Array<{foo: number}>.另一方面,在c,typeof a出现在您编写值表达式的位置,因此它是JavaScript typeof运算符,并将"object"在运行时求值为字符串.


正如@ k0pernikus所提到的,TypeScript不允许(并且不打算)允许您在运行时获取编译时类型信息.因此,没有typeof运算符在运行时执行并返回编译时信息.


当然,如果您想在编译时获取有关属性的类型信息,则可以使用所谓的查找类型执行此操作.让我们检查一下该getProperty()函数的返回值:

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]
Run Code Online (Sandbox Code Playgroud)

T[K]在一个类型的位置的意思是"与类型的密钥的的属性类型K类型的对象上T".由于这是类型级操作,因此您可以在编译时执行此操作,而无需声明任何类型的值TK.例如,

type RegExpFlags = RegExp['flags']; // RegExpFlags is string
const flags: RegExpFlags = 'ig';
Run Code Online (Sandbox Code Playgroud)

在这里,您正在查找对象"flags"类型的键RegExp并返回string类型,并且您可以声明类型的值,RegExp['flags']而不必在RegExp任何位置具有类型的值.


这是我能够在没有关于你需要什么的更多信息的情况下回答你的问题.希望有所帮助.祝好运!


Osc*_*car 9

这是您要找的东西吗?

type PropType<TObj, TProp extends keyof TObj> = TObj[TProp];
Run Code Online (Sandbox Code Playgroud)

并通过执行以下操作获取对象属性的类型:

type MyPropType = PropType<ObjType, '<key>'>;
Run Code Online (Sandbox Code Playgroud)

这与Pick打字稿中的使用方式相同,如果key传入了任何无效内容,它可以报告编译错误。

  • 一个更简单的解决方案是“ObjType['key']”。无需定义额外的类型,语法更易于阅读。 (96认同)
  • @astoilko,你的解决方案改变了我的生活。 (6认同)