[英]Autocompletion and Argument inference not working simultaneously on mapped types with Typescript generics
在下面的代碼( Playground )中,我嘗試同時在personTypeX({...})
中進行自動完成和函數簽名推斷,但我只能實現其中一個,但不能同時實現兩者。
甚至可能嗎?
以下是要求:
firstName
,那么它必須是一個string
。age
,那么它一定是一個number
。firstName
、 lastName
、 age
、 favouriteFood
也不是getLegCount
,那么該屬性的值本身必須是Person
。總共有 3 項附加要求
personType1()
和personType2()
一起使用personTypeX({})
中提供firstName
、...、 getLegCount
中所有鍵的自動完成功能,見下文:目前僅適用於personType2({})
getLegCount
)強制它的值是一個函數,那么函數簽名必須正確推斷如下:目前僅適用於personType1({})
type FixedType = {
firstName: string,
lastName: string,
age: number,
favouriteFood: string[],
getLegCount: (numHeads: number) => number,
};
type PersonType<T> = {
[K in (keyof T | keyof FixedType)]?:
K extends keyof FixedType
? FixedType[K]
: K extends keyof T
? T[K] extends object
? PersonType<T[K]>
: PersonType<{}>
: never
}
// ---- ---- ---- ---- ----
function personType1<T extends PersonType<T>>(t: T) { // signature version 1
return t;
}
const person11 = personType1({
firstName: 'Mark',
lastName: 'Antony',
holger: {
age: 12,
paul: {
// <-- type 'a' for autocompletion of 'age' => NOT WORKING
favouriteFood: ['cheese'],
firstName: 'Paul',
getLegCount: (numHeads) => 2, // <-- hover over 'numHeads' => numHeads: number correctly inferred => WORKING
}
},
});
// ----
function personType2<T extends PersonType<T>>(t: T & PersonType<T>) { // signature version 2
return t;
}
const person1 = personType2({
firstName: 'Mark',
lastName: 'Antony',
holger: {
age: 12,
paul: {
// <-- type 'a' for autocompletion of 'age' => WORKING
favouriteFood: ['cheese'],
firstName: 'Paul',
getLegCount: (numHeads) => 2, // <-- hover over 'numHeads' => numHeads: any inferred => NOT WORKING
// that's probably bc it's the most common signature for
// (property) getLegCount: ((numHeads: any) => number) & ((numHeads: number) => number)
// but I have no clue how to fix this
}
},
});
簡而言之,您所要求的目前是不可能的(據我所知)。
這里有很多循環邏輯,這是 TS 的限制(在管理/理解此類代碼方面只是對人類的侮辱)。 我們在泛型中使用泛型有效地規避了它,但我們仍然受到它的限制。 即,據我了解,我們只能選擇一個:
getLegCount: (numHeads) => 2
),使其成為參數的數據類型(IE.argument inferencing on non-explicit types )這方面的一個例子是當我們回到泛型是如何制作的
function example<T>(t: T)
在這里,我們可以明確定義T
以規定t
遵循,或者我們可以從t
推斷T
當我們做這樣的事情時:
function personType<T extends PersonTypeNew<T>>(t: T){...}
我們正在制作循環邏輯,並且在某些時候 TS 必須選擇T
或t
。 (即使它們相互依賴,也會產生不同的結果)。
getLegCount: (numHeads)
,我們推斷age
什么都不是(因為它不在參數中),並且不需要為age
(或任何其他鍵)提供自動完成功能。^ 這在技術上是一個超級超級簡化。 這實際上在簡單類型對象(即非循環)中得到支持,具有稱為部分推理的東西,這將允許自動完成和參數推理。
如果這令人困惑,可以在操場上提供一些示例。
無論如何,我從頭開始重寫它。 支持自動完成和參數推理,但如果后者不存在,則僅支持前者。
type PersonTypeNew<T> = {
// We have to overwrite any keys, otherwise we could incorrectly infer.
// Hence Omit<T, keyof FixedType>, we use & Partial<FixedType> for correct autocompletion
[K in keyof (Omit<T, keyof FixedType> & Partial<FixedType>)]:
K extends keyof FixedType
? FixedType[K]
: (Omit<T, keyof FixedType> & Partial<FixedType>)[K] extends Record<string, any>
? PersonTypeNew<(Omit<T, keyof FixedType> & Partial<FixedType>)[K]>
: "Invalid Value!"
}
這還會在第一層添加自動完成(當您不進行推理時)。
沒有自動補全支持會更簡潔(因為我們只是在不交叉兩個對象類型的情況下進行驗證)
type PersonTypeNewNoAutocomplete<T> = {
[K in keyof T]?:
K extends keyof FixedType
? T[K] extends FixedType[K]
? T[K]
: FixedType[K]
: PersonTypeNewNoAutocomplete<T[K]>
}
有一些未解決的問題在討論這個問題,這將進一步詳細介紹上下文引擎、優先級、循環類型的其他相關主題:
T extends M<T>
這樣的循環類型參數約束的情況下不起作用,這討論了自動完成如何不起作用檢查一下,它通過使用Partial<FixedType>
來自動完成, K extends keyof FixedType ? FixedType[K]
K extends keyof FixedType ? FixedType[K]
用於錯誤檢查和嵌套對象的遞歸泛型類型。
代碼:
type TypeCheckedInferedPerson<T> = Partial<FixedType> & PersonType<T>
type PersonType<T extends Partial<FixedType>> = {
[K in keyof T]: K extends keyof FixedType ? FixedType[K] : TypeCheckedInferedPerson<T[K]>
}
function personType2<T extends PersonType<T>>(t: TypeCheckedInferedPerson<T>) {
return t;
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.