#typescript #generics #keyof
#typescript #общие сведения #keyof
Вопрос:
У меня есть простая функция Typescript, подобная этой:
function getProperty<T, K extends keyof T>(obj: T, key: K): number {
return obj[key]; // This line is not compiling.
// Typescript will yell: "Type 'T[K]' is not assignable to type 'number'."
}
Мое использование выглядит следующим образом:
const someObj = {
myValue: 123,
otherProperty: '321'
}
getProperty(someObj, 'myValue')
Я не буду знать, какой будет структура someObj
.
Мой вопрос: как я могу указать, что T[K]
является типом number статически?
Комментарии:
1. @T.J.Crowder Я обновил свой вариант использования, спасибо!
Ответ №1:
Если объекты, с которыми вы работаете, достаточно типизированы, чтобы их форма была известна typescript, вы вполне можете сделать это [ссылка на typescript playgrounds, если хотите немного поэкспериментировать].
Вам просто нужно сузить, какие идентификаторы key
могут быть, до одного из этих ссылочных number
свойств типа:
const someObj = {
myValue: 123,
otherProperty: '321'
};
getProperty(someObj, 'myValue'); // works
getProperty(someObj, 'otherProperty'); // wails
function getProperty<T, K extends NumericProps<T>>(obj: T, key: K): number {
return obj[key];
}
type NumericProps<T> = {
[K in keyof T]: T[K] extends number ? K : never
}[keyof T];
Ответ №2:
Я не буду знать, какой будет структура
someObj
.
Тогда TypeScript не сможет вам в этом помочь. Проверка типа TypeScript выполняется во время компиляции. Если структура someObj
будет известна только во время выполнения, TypeScript не сможет обеспечить доступ к этой структуре с сохранением типов. Вам нужно было бы знать, каковы ключи свойств и возможные значения для этих свойств во время компиляции.
Например: В вашем примере имена свойств являются строками, а значения свойств — либо строками, либо числами (но не логическими значениями или объектами и т.д.). Вы можете объявить тип, индексируемый строками (поскольку все имена свойств в конечном счете являются строками или символами, в данном случае строками), где значениями свойств являются числа или строки:
declare type SomeObjType = {
[key: string]: number | string
};
и тогда getProperty
это:
function getProperty<T extends SomeObjType>(obj: T, key: string): number | string {
return obj[key];
}
и вы можете использовать это следующим образом (в данном случае я использую JSON.parse
для имитации получения этих данных из-за пределов программы):
const someObj: SomeObjType = JSON.parse(`{
"myValue": 123,
"otherProperty": "321"
}`);
console.log(getProperty(someObj, 'myValue'));
console.log(getProperty(someObj, 'otherProperty'));
<a rel="noreferrer noopener nofollow" href="https:///www.typescriptlang.org/play/index.html#src=declare type SomeObjType = {
[key: string]: number | string
};
function getProperty(obj: T, key: string): number | string {
return obj[key];
}
const someObj: SomeObjType = JSON.parse(`{
«myValue»: 123,
«otherProperty»: «321»
}`);
console.log(getProperty(someObj, ‘myValue’));
console.log(getProperty(someObj, ‘otherProperty’));» rel=»nofollow noreferrer»>На игровой площадке
Но это мало что дает и исключает возможность того, что значения свойств являются чем-то иным, чем числами или строками.
Возможно, вам потребуется просто использовать object
:
function getProperty(obj: object, key: string) {
return obj[key];
}
const someObj = JSON.parse(`{
"myValue": 123,
"otherProperty": "321"
}`);
console.log(getProperty(someObj, 'myValue'));
console.log(getProperty(someObj, 'otherProperty'));
Комментарии:
1. Вау, спасибо за подробное объяснение,
T extends SomeObjType
подходит для моего варианта использования! Спасибо!