Использование имени свойства в объявлении typescript

#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) кажется аккуратным (на первый взгляд), и я хочу исследовать эти области. Я надеялся, что есть способ правильно вводить подобные конструкции.