简体   繁体   English

使用对象文字的键作为 Typescript 类型?

[英]Using the keys of an object literal as a Typescript type?

I have an object which contains some predefined data for my application, which is stored in a const variable like this:我有一个对象,其中包含我的应用程序的一些预定义数据,它存储在一个常量变量中,如下所示:

const data:{[key:string]:any} =Object.freeze({
    some: 123,
    long: {"a":"b"},
    list: ["c"],
    of: "",
    arbitrary: null,
    things: 1.2,
});

The keys of this object are known to the rest of the application.该对象的键对于应用程序的其余部分是已知的。 Consider this function which accesses the data object:考虑这个访问数据对象的函数:

function doWork(k) {
    if(!data.hasOwnProperty(k)) throw Error();
    let value = data[k];
    //...
}

This is called with strings like这被称为字符串

doWork("things");

I would like to replace that runtime error for invalid keys with a Typescript compile-time check.我想用 Typescript 编译时检查替换无效键的运行时错误。 I would like to be able to write我希望能够写

function doWork(k: keyof data) {
    let value = data[k];
    //...
}

But apparently the keyof operator does not work that way.但显然keyof运算符不能那样工作。 I get an error TS2304: Cannot find name 'data'.我收到错误TS2304: Cannot find name 'data'.


My workaround: I can extract the keys of the object with something like this:我的解决方法:我可以用这样的东西提取对象的键:

console.log("\""+Object.keys(data).join("\"|\"")+"\"");

Which I can then copy/paste and define as a type.然后我可以复制/粘贴并定义为类型。

type data_key = "some"|"long"|"list"|"of"|"arbitrary"|"things"
export function doWork(k:data_key) {
    let value = data[k];
    //...
}

This feels like a silly hack and is quite inconvenient whenever I have to make a change, because I have to remember to put in this statement at the right place, run the program, and manually copy in the values back into the source code (or realistically, just type in the changes myself).这感觉就像一个愚蠢的 hack 并且每当我必须进行更改时都非常不方便,因为我必须记住将此语句放在正确的位置,运行程序,然后手动将值复制回源代码(或实际上,只需自己输入更改即可)。


I am open to a better solution.我对更好的解决方案持开放态度。 Is there a language feature that provides the functionality I am looking for?是否有提供我正在寻找的功能的语言功能?

Let TypeScript infer the type of data , then extract the keys from the type it infers by using type data_key = keyof typeof data;让 TypeScript 推断data的类型,然后使用type data_key = keyof typeof data;从它推断的类型中提取键type data_key = keyof typeof data; :

const data = Object.freeze({
    some: 123,
    long: {"a":"b"},
    list: ["c"],
    of: "",
    arbitrary: null,
    things: 1.2,
});

type data_key = keyof typeof data;

function doWork(k: data_key) {
    let value = data[k];
    //...
}

On the playground. 操场上。

How that works:它是如何工作的:

  1. TypeScript has advanced type inference and so is able to infer the type of the object initializer passed into Object.freeze with the keys some , long , list , etc. Object.freeze is defined as freeze<T>(o: T): Readonly<T> ¹ so it returns a Readonly version of that same inferred type. TypeScript 具有高级类型推断,因此能够推断传递给Object.freeze的对象初始值设定项的类型,键为somelonglist等。 Object.freeze被定义为freeze<T>(o: T): Readonly<T> ¹ 所以它返回相同推断类型的Readonly版本。
  2. keyof gets the keys of a type. keyof获取类型的键。
  3. typeof in this context is TypeScript's typeof , not JavaScript's. typeof在这个上下文中是 TypeScript 的typeof ,而不是 JavaScript 的。 In TypeScript, there are places it expects runtime value, and other places it expects compile-time types.在 TypeScript 中,有些地方需要运行时值,有些地方需要编译时类型。 keyof 's operand is a place where a compile-time type is expected, so typeof data returns the compile-time type of data , which is the Readonly version of the inferred type from freeze (with the keys some , long , list , etc.). keyof的操作数是需要编译时类型的地方,因此typeof data返回编译时类型的data ,这是从freeze推断类型的只读版本(键为somelonglist等.) (If you had x = typeof data , that would be typeof in a context where a runtime value is expected, so it would be JavaScript's typeof , and x would get the runtime value "object" .) (如果您有x = typeof data ,那么在需要运行时值的上下文中将是typeof ,因此它将是 JavaScript 的typeof ,而x将获得运行时值"object" 。)

¹ There are actually three definitions of freeze in lib.es5.d.ts (one for arrays, one for functions, and one for all other kinds of objects; this is that last one). ¹ lib.es5.d.ts中实际上有三种freeze定义(一种用于数组,一种用于函数,一种用于所有其他类型的对象;这是最后一种)。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM