在typescript声明中使用属性名



有没有办法在Typescript类型定义中获取/使用实际的属性名?

type Mapped = {
[P:string]: P;
}

其中Mapped["foo"]"foo"型,Mapped["bar"]"bar"型,而非string型。

我尝试了[P:string],[P in keyof any],typeof P,readonlyas consttype Mapped<Props extends keyof any> = { [P in Props]: P }的不同变化,以及我沿着这些行想到的一切,但P最多输入为string,从未作为实际的属性名称。

我需要这个做什么?

以…为基础使用访问的属性名动态生成实用程序函数的键入代理。

类似

type GetProperty = {
[P in (keyof any)]: <T>(obj:T) => P extends keyof T ? T[P] : void;
}

我的问题是,由于生成/返回的值是动态的,我没有类型Tkeyof T的名称。

你能提供一个期望行为的例子吗?

var obj:Mapped = new Proxy(...);
// where the properties of `obj` should be typed as
var foo:"foo" = obj.foo;
var bar:"bar" = obj.bar;

obj.asdf1234的类型应为"asdf1234"

在TypeScript中不能这样做。在microsoft/TypeScript#22509上有一个开放的特性请求,它要求这个功能,如果你认为它特别引人注目,你可以自由地去那里给它一个👍或描述你的用例,我想说它发生的可能性很低。从这个评论:

用我们当前的类型系统特性根本不可能对其建模(因为没有任何东西允许您在属性访问中捕获与属性名称对应的文字类型)。

所以如果我是你,我不会屏住呼吸。


我的建议是放弃动态属性键,而是尝试单个方法将所需的键作为参数:

const obj = {
get<P extends PropertyKey>(p: P) {
return <T,>(t: T): P extends keyof T ? T[P] : void =>
(t as any)[p]
}
}

const foo = {
a: 1,
b: "two",
c: true
}
console.log(obj.get("a")(foo).toFixed(2)); // 1.00
console.log(obj.get("b")(foo).toUpperCase()); // TWO
obj.get("z")(foo) // void

或者,在这种情况下,您还不如直接使用函数而不是方法:

function getter<P extends PropertyKey>(p: P) {
return <T,>(t: T): P extends keyof T ? T[P] : void =>
(t as any)[p]
}
console.log(getter("a")(foo).toFixed(2)); // 1.00
console.log(getter("b")(foo).toUpperCase()); // TWO
getter("z")(foo) // void

的想法是,而不是obj.a(foo)你有obj.get("a")(foo)或只有getter("a")(foo)。它有相同的功能,但它的包装有点不同。它可能不是你想要的那种形式,但至少它有一个优点:TypeScript可以表示它在做什么!

Playground链接到代码

最新更新