簡體   English   中英

TypeScript:是否可以安全地訪問給定鍵數組的 object 的嵌套屬性? 這可以以類型安全且可組合的方式完成嗎?

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM