[英]TypeScript: Is it possible to safely access nested properties of an object given an array of keys? Can this be done in a type safe and composable way?
我想寫一個 function,它從給定屬性鍵數組的 object 中獲取一個值。 它看起來像這樣:
function getValue<O, K extends ObjKeys<O>>(obj: O, keys: K): ObjVal<O,K> {
let out = obj;
for (const k in keys) out = out[k]
return out
}
我希望這個 function 像這樣工作:
type Foo = {
a: number
b: string
c: {
lark: boolean
wibble: string
}
}
let o: Foo = {
a: 1,
b: "hi",
c: {
lark: true,
wibble: "there"
}
}
// I'd like these to type check (and return the expected values):
getValue(o, ['a']) // returns 1
getValue(o, ['b']) // returns "hi"
getValue(o, ['c','lark']) // returns true
// I'd like these _not_ to type check:
getValue(o, ['a','b'])
getValue(o, ['d'])
重要的是,我希望有一個類型(如上例中的ObjKeys<O>
)可用,這樣我就可以在其他函數中輕松地使用這個 function,同時保留鍵入。 例如我可能想做這樣的事情:
function areValuesEqual<O>(obj: O, oldObj: O, keys: ObjKeys<O>) {
let value = getValue(obj, keys)
let oldValue = getValue(oldObj, keys)
return value === oldValue ? true : false
}
這個 function 獲取一些鍵並將它們傳遞給我們上面的getValue
,理想情況下它會進行所有類型檢查,因為 object O
和鍵ObjKeys<O>
都是有效的 arguments 到內部調用的getValue
function。
這擴展到返回getValue
返回的值; 我可能還想做這樣的事情:
function doSomethingAndThenGetValue<O>(obj: O, oldObj: O, keys: ObjKeys<O>): ObjVal<O> {
let value = getValue(obj, keys)
console.log("Value obtained is:", value)
return value
}
這也使用類似ObjVal<O>
的東西來知道返回類型是什么,因此將進行完全類型檢查。
是否有解決方案,或者根本沒有辦法在 TypeScript 中執行此類操作(撰寫本文時為第 4 版)?
我可以定義一個function允許嵌套訪問,如下所示:
function getValue<
O extends object,
K1 extends keyof O
>(obj: O, keys: [K1]): O[K1]
function getValue<
O extends object,
K1 extends keyof O,
K2 extends keyof O[K1]
>(obj: O, keys: [K1,K2]): O[K1][K2]
function getValue<
O extends object,
K1 extends keyof O,
K2 extends keyof O[K1],
K3 extends keyof O[K1][K2]
>(obj: O, keys: [K1,K2,K3]): O[K1][K2][K3]
function getValue<O>(obj: O, keys: Key | (Key[])): unknown {
let out = obj;
for (const k in keys) out = out[k]
return out
}
type Key = string | number | symbol
然后當我嘗試訪問值時,這個類型檢查正確(在這種情況下最多 3 層)。
但是,當我想在保持類型安全的同時使用另一個 function 時,我有點卡住了:
function areValuesEqual<O>(obj: O, oldObj: O, keys: ????) {
let value = getValue(obj, keys)
let oldValue = getValue(oldObj, keys)
return value === oldValue ? true : false
}
function doSomethingAndThenGetValue<O>(obj: O, oldObj: O, keys: ????): ???? {
let value = getValue(obj, keys)
console.log("Value obtained is:", value)
return value
}
我不確定我可以用什么來代替????
告訴 TypeScript 這些類型如何相互關聯,以便進行類型檢查。 每次我想編寫上述函數時,我是否可以避免重寫我的大量重載,但仍能得到我想要的類型檢查?
我想編寫一個函數,該函數從給定屬性鍵數組的對象中獲取值。 它看起來像這樣:
function getValue<O, K extends ObjKeys<O>>(obj: O, keys: K): ObjVal<O,K> {
let out = obj;
for (const k in keys) out = out[k]
return out
}
我希望此功能可以這樣工作:
type Foo = {
a: number
b: string
c: {
lark: boolean
wibble: string
}
}
let o: Foo = {
a: 1,
b: "hi",
c: {
lark: true,
wibble: "there"
}
}
// I'd like these to type check (and return the expected values):
getValue(o, ['a']) // returns 1
getValue(o, ['b']) // returns "hi"
getValue(o, ['c','lark']) // returns true
// I'd like these _not_ to type check:
getValue(o, ['a','b'])
getValue(o, ['d'])
重要的是,我希望有一個類型(如上例中的ObjKeys<O>
)可用,以便我可以輕松地從其他函數中使用此函數,同時保留鍵入內容。 例如,我可能想做這樣的事情:
function areValuesEqual<O>(obj: O, oldObj: O, keys: ObjKeys<O>) {
let value = getValue(obj, keys)
let oldValue = getValue(oldObj, keys)
return value === oldValue ? true : false
}
此函數需要一些鍵並將它們傳遞給上面的getValue
,並且理想情況下將全部進行類型檢查,因為對象O
和鍵ObjKeys<O>
都是內部調用的getValue
函數的有效參數。
這擴展到返回由getValue
返回的值; 我可能還想做這樣的事情:
function doSomethingAndThenGetValue<O>(obj: O, oldObj: O, keys: ObjKeys<O>): ObjVal<O> {
let value = getValue(obj, keys)
console.log("Value obtained is:", value)
return value
}
這也使用ObjVal<O>
類的東西來知道返回類型是什么,因此也將進行完全類型檢查。
有沒有解決的辦法,或者根本就沒有辦法在TypeScript中做這種事情(撰寫本文時為版本4)?
我可以定義一個允許嵌套訪問的函數,如下所示:
function getValue<
O extends object,
K1 extends keyof O
>(obj: O, keys: [K1]): O[K1]
function getValue<
O extends object,
K1 extends keyof O,
K2 extends keyof O[K1]
>(obj: O, keys: [K1,K2]): O[K1][K2]
function getValue<
O extends object,
K1 extends keyof O,
K2 extends keyof O[K1],
K3 extends keyof O[K1][K2]
>(obj: O, keys: [K1,K2,K3]): O[K1][K2][K3]
function getValue<O>(obj: O, keys: Key | (Key[])): unknown {
let out = obj;
for (const k in keys) out = out[k]
return out
}
type Key = string | number | symbol
然后,當我嘗試訪問值時,此類型檢查正確(在這種情況下,深度最多為3層)。
但是,當我想在保留類型安全性的同時從另一個函數使用該函數時,我有點卡住了:
function areValuesEqual<O>(obj: O, oldObj: O, keys: ????) {
let value = getValue(obj, keys)
let oldValue = getValue(oldObj, keys)
return value === oldValue ? true : false
}
function doSomethingAndThenGetValue<O>(obj: O, oldObj: O, keys: ????): ???? {
let value = getValue(obj, keys)
console.log("Value obtained is:", value)
return value
}
我不確定我可以代替什么????
告訴TypeScript類型如何相互關聯,以便進行類型檢查。 我是否可以避免每次想編寫上述函數時都必須重寫大量的重載列表,但是仍然需要進行類型檢查?
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.