[英]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"
}
]
});
一些背景信息:我正在編寫一個程序,其中定義了一些“動作”。 每個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 }>
}
這意味着,給定K
個value
屬性,我們希望Opt<K>
的items
屬性是一個數組,其中數組的元素是具有類型K
的value
屬性的對象,以及輸入類型為K
的func
回調屬性.
讓我們通過評估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;
}[];
} */
看起來挺好的。
無論如何,如上所述, makeObj
在K
中將是通用的,並采用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.