#typescript #typescript-typings
#typescript #typescript-типизации
Вопрос:
Есть ли способ получить / использовать фактическое имя свойства в определении типа Typescript.
type Mapped = {
[P:string]: P;
}
Где Mapped["foo"]
имеет тип "foo"
и Mapped["bar"]
имеет тип "bar"
, а не string
.
Я пробовал разные варианты [P:string]
, [P in keyof any]
, typeof P
, readonly
и as const
или type 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;
}
Моя проблема в том, что, поскольку сгенерированные / возвращаемые значения являются динамическими, у меня нет типа T
для keyof 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"
Комментарии:
1. Не могли бы вы привести пример ожидаемого поведения?
2. @captain-yossarian объясняет ли это, чего я пытаюсь достичь?
Ответ №1:
Это невозможно сделать в 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 может представлять, что он делает!
Комментарии:
1. Спасибо за подробный ответ. Я знаю, что могу использовать для этого функцию. В настоящее время я играю с прокси, и будут ли такие конструкции использоваться. Что-то вроде
array.map(property.name)
кажется аккуратным (на первый взгляд), и я хочу исследовать эти области. Я надеялся, что есть способ правильно вводить подобные конструкции.