簡體   English   中英

從父 object 推斷窄類型在 typescript 中引用自身

[英]Infer narrow type from parent object referencing itself in typescript

我想像這樣約束 object 中的回調 function 的參數類型:

makeObj({
  items: [
    {
      value: "foo",
      func(items) {}
    },
    {
      value: "bar",
      func(items) {}
    }
  ]
});

我想將func的參數items約束為"foo" | "bar" "foo" | "bar" value 的value可以是任何字符串。

我已經有了這個,但它顯然不起作用:

interface MyObject<T extends string, Values extends readonly MyObject<T, Values>[]> {
  value: T;
  func: (items: Values) => void;
}
interface Items<T extends string, Data extends readonly MyObject<T, Data>[]> {
  items: readonly [...Data];
}
function makeObj<T extends string, Data extends readonly MyObject<T, Data>[]>(opt: Items<T, Data>) {
  return opt;
}

makeObj({
  items: [
    {
      value: "foo",
      func(items) {}
/* Error on "func":
Type '(items: MyObject<string, unknown>) => void' is not assignable to type '(items: unknown) => void'.
  Types of parameters 'items' and 'items' are incompatible.
    Type 'unknown' is not assignable to type 'MyObject<string, unknown>'.
*/
    },
    {
      value: "bar",
      func(items) {} // same error on "func"
    }
  ]
});

Typescript 游樂場


一些背景信息:我正在編寫一個程序,其中定義了一些“動作”。 每個action都是一個function在一個object來描述function(給它一個名字,描述,輸入類型,output類型,輔助輸入類型)。 輔助輸入依賴於用戶提供的數據。 此數據的每一項都有一個名稱和定義的類型。 它的值由最終用戶提供。 根據其他項目的價值,一個項目是否可以顯示給用戶。 最后一部分由相關回調 function 控制。
我已經使用窄類型推斷設置了所有這些,以便在編寫每個操作時不會犯任何錯誤,但是無論回調 function 具有哪種類型,這種窄類型推斷都會失效。 要么是因為它不能再推斷出窄類型,要么是因為我收到類型錯誤(例如,當我使用object作為參數類型時(我最終想使用 object 作為參數,而不僅僅是一個字符串))。 這種窄類型推斷是這樣工作的: typescript - Infer/narrow function argument from sibling property


編輯:

我想要一個解決方案,其中我沒有在 function 參數中嵌入類型,但作為我可以引用的接口/類型,例如:

interface Magic<MagicParam> {
  items: MagicParam;
}
makeObj<MagicParam>(opt: Magic<MagicParam>) {
  return opt;
}

Magic可以是接口或類型,並且可以有任意數量的類型參數。 makeObj也可以有任意數量的類型參數。

您的makeObj() function 在與 function 參數的items屬性的value屬性相對應的字符串文字類型聯合中可以是通用的。 如果我們調用該通用類型參數K ,並且如果您傳入,例如{items: [{value: "x"},{value: "y"},{value: "z"}]} (忽略func現在),那么K應該是"x" | "y" | "z" "x" | "y" | "z"

然后您可以根據K表達makeObj()的參數。 如果我們調用該類型Opt<K> ,我們可以這樣寫:

interface Opt<K extends string> {
  items: Array<{ value: K, func: (items: K) => void }>
}

這意味着,給定Kvalue屬性,我們希望Opt<K>items屬性是一個數組,其中數組的元素是具有類型Kvalue屬性的對象,以及輸入類型為Kfunc回調屬性.

讓我們通過評估Opt<"foo" | "bar">來確保這就是您想要的。 Opt<"foo" | "bar"> (並使用條件類型推斷映射類型來誘使編譯器顯示結構的詳細信息):

type Test = Opt<"foo" | "bar"> extends
  infer O ? { [K in keyof O]: O[K] } : never 

/* type Test = {
    items: {
        value: "foo" | "bar";
        func: (items: "foo" | "bar") => void;
    }[];
} */

看起來挺好的。


無論如何,如上所述, makeObjK中將是通用的,並采用Opt<K>類型的參數:

function makeObj<K extends string>(opt: Opt<K>) {
  return opt;
}

讓我們看看它是否有效:

const obj = makeObj({
  items: [
    {
      value: "foo",
      func(items) {
        // (parameter) items: "foo" | "bar"
      }
    },
    {
      value: "bar",
      func(items) {
        // (parameter) items: "foo" | "bar"
      }
    }
  ]
});
// const obj: Opt<"foo" | "bar">

看起來也不錯。 編譯器推斷K"foo" | "bar" "foo" | "bar" ,然后根據上下文func屬性的items回調參數鍵入為"foo" | "bar" "foo" | "bar" 出來的obj是所需的Opt<"foo" | "bar"> Opt<"foo" | "bar">類型。

游樂場代碼鏈接

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

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