[英]Typescript - How to access a variable object property from a variable object
我在嘗試編寫一個接受兩個輸入的函數時遇到了一些困難:
並打印該對象的該屬性的值。 然而,這些對象都有不同的屬性,它們並不完全相同。
對象如下所示:
class object1 {
get property1() {
return 'foo';
}
get property2() {
return 'bar';
}
}
export default new object1();
class object2 {
get different1() {
return 'asdf';
}
get different2() {
return 'ghjk';
}
}
export default new object2();
到目前為止,這是我嘗試過的:
import object1 from '..';
import object2 from '..';
getPropertValue(objectName, propertyName) {
let objects = [object1, object2];
let index = objects.indexOf(objectName);
console.log(objects[index][propertyName]);
}
這沒有用,返回為未定義。 似乎 index 計算正確,但objects[index][propertyName]
似乎沒有正確訪問對象的值。 雖然很奇怪,但當我嘗試以下操作時,它幾乎起作用了:
import object1 from '..';
import object2 from '..';
getPropertValue(objectName, propertyName) {
let objects = [object1, object2];
for (let index in objects) {
console.log(objects[index][propertyName]);
}
}
在這里我實際上讓它打印了正確的值,但問題是因為我只是在 for 循環中遍歷所有對象,它會嘗試打印所有對象的值,而不僅僅是與 objectName 匹配的對象. 所以它為具有我試圖訪問的屬性的對象打印正確的值,但是對於沒有該屬性的另一個對象則為未定義。
我想我可以為每個名為name
的對象添加一些屬性並執行如下操作:
getPropertValue(objectName, propertyName) {
let objects = [object1, object2];
for (let index in objects) {
if(objects[index].name == objectName) {
console.log(objects[index][propertyName]);
}
}
}
但如果可以的話,我寧願不向這些對象添加不必要的屬性。
有一個更好的方法嗎?
對象可以被變量引用,但是對象沒有被命名的特性,除非您的代碼明確地將其作為數據模型的一部分提供。
例如:
const obj = { abc: 123 }
這里的值{ abc: 123 }
沒有命名為obj
。 有一個標識符為obj
的變量引用了{ abc: 123 }
的值。
這在實踐中意味着,如果您只有對{ abc: 123 }
的引用,那么您無法知道還有哪些其他變量標識符也持有對該值的引用。
而且您不能通過標識符作為字符串來獲取變量的值。
所以這不可能工作:
const foo = 'bar'
function getVar(varName: string) {
// impossible function implementation here.
}
getVar('foo') // expected return value: 'bar'
但是您可以擁有的是具有屬性的對象。 屬性具有特定字符串的鍵。
const objects = { // note the {}, [] is for arrays
object1,
object2,
}
這是以下內容的簡寫:
const objects = {
"object1": object1,
"object2": object2,
}
您現在擁有的對象的屬性與您要用於對象的名稱相對應。
最后,讓我們正確輸入您的函數:
// store this outside the function
const objects = {
object1,
object2,
}
function getPropertyValue<
T extends keyof typeof objects
>(
objectName: T,
propertyName: keyof typeof objects[T]
) {
console.log(objects[objectName][propertyName]);
}
這個函數現在是通用的,這意味着它接受一個類型。 在這種情況下,它接受您要用作T
的對象名稱,它是objects
對象的任何keyof
。
然后propertyName
參數使用任何鍵來找出應該允許的屬性,方法是將類型限制為這些對象之一的屬性。
現在要獲取數據,您可以通過objects
上的屬性名稱鑽取objects
,然后再次鑽取特定屬性名稱。
用法如下所示:
getPropertyValue('object1', 'property1') // 'foo'
getPropertyValue('object2', 'different1') // 'asdf'
getPropertyValue('object1', 'different1')
// Type error, 'different1' does not exist on 'object1'
正如 Alex Wayne 所解釋的那樣:對象將僅具有“作為數據模型的一部分”的名稱。
或者換句話說:對象的名稱就是您將其關聯的對象。
這種聯系可能來自內部或外部。 例子:
// Name by self-definition
const someObject = { name: "self-named" };
// Name by association
const nameToObject = { "associated-name": {} };
為避免向對象添加不必要的屬性,我將使用“關聯名稱”方法:
const objects = { object1, object2 };
旁注:在此速記對象初始化中,標識符用作屬性名稱,它們的引用用作屬性值。
有了這個,實現就很簡單了:
const object1 = new class Object1 { get property1() { return "foo"; } get property2() { return "bar"; } }; const object2 = new class Object1 { get different1() { return "asdf"; } get different2() { return "ghjk"; } }; const objects = { object1, object2 }; // The implementation function getPropertyValue(objectName, propertyName) { return objects[objectName][propertyName]; } const value = getPropertyValue("object1", "property2"); console.log(value);
要添加正確的類型,我們需要考慮輸出如何依賴於輸入。 而且,輸入如何相互依賴。
一個天真的實現可能是這樣的:
function getPropertyValue(
objectName: "object1" | "object2",
propertyName: "property1" | "property2" | "different1" | "different2"
): any;
但這並沒有完全利用 Typescript 的能力。 根據objectName
的值,只能使用propertyName
的原始類型的子集: propertyName
取決於objectName
。
由於函數參數之間存在依賴關系,因此我們需要一個通用參數來鏈接它們。
多虧了我們的字典,我們已經知道objectName
的哪個值對應於哪個類型。 我們只需要將propertyName
限制為該類型的鍵:
type Objects = typeof objects;
function getPropertyValue<
K extends keyof Objects
>(
objectName: K,
propertyName: keyof Objects[K]
);
調用此函數時,默認會從objectName
推斷出K
,並根據我們的輸入自動限制我們對propertyName
的選擇。
雖然(特別是聲明為const
的)變量可以引用對象,但它們的標識符(即變量名)通常不被視為其引用對象的名稱。 有充分的理由!
您無法通過標識符輕松查找對象。 為此,需要new Function
或eval()
,它們以存在安全問題而著稱。
因此,請將以下內容視為示范,而非推薦:
const object1 = { name: "Object-1" }; const object2 = { name: "Object-2" }; const o = getObjectByName("object1"); console.log(o); function getObjectByName(name) { // You should avoid new Function; return new Function(`return ${name};`)(); }
for...in
, for...of
,為了什么? 有多個for
循環:
確保您熟悉這些!
提示:在許多情況下,您可以使用Object.keys()
或.entries()
而不是for...in
循環,這樣可以避免與for...of
循環混淆。
我們不想為每個函數調用實例化objects
,這意味着它需要在該函數之外。
但是天真地將它移到外面會污染命名空間。
相反,我們可以使用閉包來僅實例化它一次,但將其隱藏在全局范圍之外:
// Mock imports const object1 = { property1: "foo", property2: "bar" }; const object2 = { different1: "asdf", different2: "ghjk" }; const getPropertyValue = (() => { const objects = { object1, object2 }; return function(objectName, propertyName) { return objects[objectName][propertyName]; }; })(); const value = getPropertyValue("object1", "property2"); console.log(value); console.log(objects);
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.