我有一个对象,其中包含我的应用程序的一些预定义数据,这些数据存储在这样的const变量中:
const data:{[key:string]:any} =Object.freeze({
some: 123,
long: {"a":"b"},
list: ["c"],
of: "",
arbitrary: null,
things: 1.2,
});
该对象的键对于应用程序的其余部分是已知的。考虑以下访问数据对象的函数:
function doWork(k) {
if(!data.hasOwnProperty(k)) throw Error();
let value = data[k];
//...
}
这用类似的字符串来调用
doWork("things");
我想用Typescript编译时检查替换无效键的运行时错误。我希望能够写
function doWork(k: keyof data) {
let value = data[k];
//...
}
但是显然keyof
运算符不能那样工作。我收到错误消息TS2304: Cannot find name 'data'.
我的解决方法: 我可以用以下方法提取对象的键:
console.log("\""+Object.keys(data).join("\"|\"")+"\"");
然后我可以复制/粘贴并定义为类型。
type data_key = "some"|"long"|"list"|"of"|"arbitrary"|"things"
export function doWork(k:data_key) {
let value = data[k];
//...
}
这感觉很愚蠢,每当需要进行更改时,都会感到非常不便,因为我必须记住在正确的位置放置此语句,运行程序,然后手动将值复制回源代码中代码(或者实际上,只需自己输入更改)。
我愿意寻求更好的解决方案。是否有语言功能可以提供我要寻找的功能?
答案 0 :(得分:8)
让TypeScript推断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];
//...
}
工作原理:
Object.freeze
,some
,long
来推断传入list
的对象初始化程序的类型。 ,等等。Object.freeze
被定义为freeze<T>(o: T): Readonly<T>
¹,因此它返回相同推断类型的Readonly
版本。keyof
获取类型的键。typeof
是TypeScript的typeof
,而不是JavaScript的。在TypeScript中,有一些地方需要运行时值,而其他地方则需要编译时类型。 keyof
的操作数是需要编译时类型的地方,因此typeof data
返回data
的编译时类型,它是从{推断出的类型的只读版本{1}}(使用键freeze
,some
,long
等)。 (如果您有list
,则在期望运行时值的上下文中为x = typeof data
,因此它将是JavaScript的typeof
,而typeof
将获得运行时值x
。)¹lib.es5.d.ts
中实际上有"object"
的三个定义(一个用于数组,一个用于函数,以及一个用于所有其他类型的对象;这是最后一个)。