【问题标题】:Getting type of a property of a typescript class using keyof operator使用 keyof 运算符获取 typescript 类的属性类型
【发布时间】:2018-02-04 06:41:20
【问题描述】:

正如 Typescript 关于keyof 运算符的文档中所述,可以使用以下函数获取对象实例的属性。

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

当然,可以通过将return o[name] 替换为return typeof o[name] 来获取属性的类型。有没有办法在不传递任何对象实例的情况下检索属性的类型?

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

【问题讨论】:

  • 根据 TypeScript 的无目标编号 5:“在程序中添加或依赖运行时类型信息,或根据类型的结果发出不同的代码”恐怕这可能是不可能的因为这听起来像是对我的类型反射你正在尝试做的事情。 github.com/Microsoft/TypeScript/wiki/TypeScript-Design-Goals
  • @k0pernikus 我不认为这个问题需要任何与运行时信息相关的东西或由于类型而导致的不同代码编译。都是静态类型。

标签: typescript


【解决方案1】:

这是你要找的吗?

type PropType<TObj, TProp extends keyof TObj> = TObj[TProp];

并通过以下方式获取对象属性的类型:

type MyPropType = PropType<ObjType, '<key>'>;

这和typescript中使用Pick的方式一样,如果传入无效的key会报编译错误。

更新

正如@astoilkov 所建议的,一个更简单的选择是PropType['key']

【讨论】:

  • 一个更简单的解决方案是ObjType['key']。不需要定义额外的类型,语法更容易阅读。
  • 谢谢,我更喜欢简写,例如private connection: Database['connection'];.
  • @astoilko,您的解决方案改变了我的生活。 ?
【解决方案2】:

是的,lookup types 应该可以正常工作。喜欢:

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

type BarType = FooType['bar']; // BarType is a string now

【讨论】:

  • 请注意,如果使用 eslint,您需要确保使用“新”@babel/eslint-parser 库以避免语法错误。更多细节在thisgithub 问题中。
  • 如果您因为FooType 可以为空或未定义而遇到问题,请使用NonNullabletype BarType = NonNullable&lt;FooType&gt;['bar']
【解决方案3】:

当然,可以通过将return o[name] 替换为return typeof o[name] 来获取属性的类型。

不是真的......如果你这样做了:

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

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

TypeScript 还使用关键字 typeof 作为编译时 type query operator。您可以通过查看它出现的位置来分辨差异。类型查询typeof 仅出现在您正在编写类型 的地方。例如:

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

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


正如@k0pernikus 所提到的,TypeScript 不允许(也不打算)允许您在运行时获取编译时类型信息。所以没有typeof 运算符在运行时起作用并返回编译时信息。


当然,如果您想在编译时获得有关属性的类型信息,您可以这样做,使用所谓的lookup types。让我们检查一下 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]

在类型位置的T[K] 表示“在T 类型的对象上具有K 类型键的属性类型”。由于这是一个类型级别的操作,您可以在编译时执行此操作,而无需声明 TK 类型的任何值。例如,

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

在这里,您正在查找RegExp 对象类型的"flags" 键并返回string 类型,并且您可以声明RegExp['flags'] 类型的值而没有@987654356 类型的值@任何地方。


这是我能回答您的问题的最接近的方法,而无需提供有关您需要什么的更多信息。希望有帮助。祝你好运!

【讨论】:

  • 你好,谢谢你的回答,对我来说似乎有点难以理解;您能否举例说明如何在编译时获取类属性的类型(例如字符串)?谢谢
  • 有关lookup types(也称为“索引访问类型”)的文档有帮助吗?如果您有class Foo { bar: string = "baz" },然后是type FooBar = Foo["bar"],则FooBar 类型将为string
  • 查找类型的文档非常抽象,究竟什么是“type Foobar”?我需要的是一个描述类型的字符串,比如“String”或“Number”;最后起作用的是blog.wolksoftware.com/…
猜你喜欢
  • 2021-11-13
  • 2017-12-28
  • 2022-08-11
  • 2023-04-07
  • 2022-06-10
  • 1970-01-01
  • 2019-12-26
  • 2021-02-22
相关资源
最近更新 更多