我有以下型別的代碼:
type StrictPropertyCheck< T, TExpected> = Exclude<keyof T, keyof TExpected> extends never ? Record<string, unknown> : 'TypeWithStrictPropertyCheck'。
export const check = <
T1 extends Record<string, string | string[]> 。
T2 extends T1 & StrictPropertyCheck<T2, T1> 。
>(arg: {
myKey: [T1, ...T2[] ]
}): {
myKey: T1[] 。
} => {
return arg
}
export const template = check({
myKey: [{ {
a: ''/span>,
b: [''/span>]。
c: ['', ''].
}, {
a: '',
b: [''/span>]。
c: ['', ''].
}]
})
check函式檢查陣列myKey中的所有物件的鍵和每個索引的鍵型別是否相同。
我怎樣才能代替在函式arg輸入中明確輸入myKey,接受任何數量的具有任何給定名稱的鍵,并且仍然對每個與單個鍵相關的陣列執行相同的檢查?
簡而言之;我希望arg能接受任何鍵,而不是一個明確的鍵。
編輯:
每個arg-key的陣列應該由物件組成,其中每個物件的key-name與陣列中第一個物件的key-name完全相同。此外,每個物件中的每個物件-鍵的關鍵型別,必須與第一個物件中相應的關鍵名稱的關鍵型別相匹配。每個物件中的關鍵型別可以是string[]或者string。
(這就是檢查函式所做的,只是不針對任何arg-key)
uj5u.com熱心網友回復:
你可以采取的一種方法是將你的T1和T2型別引數變成物件型別,對于每個屬性鍵K in keyof T1,屬性值T1[K]和T2[K]就像你原來的T1和T2值。 這就產生了這樣的代碼:
export const check = <
T1 extends { [K in keyof T1] 。Record<string, string | string[]> },
T2 extends { [K in keyof T1] 。T1[K] & StrictPropertyCheck<T2[K], T1[K]> },
>(arg: { [K in keyof T1]: [T1[K], ...T2[K][ ] ] . }) => arg;
我認為它是可行的:
check( {
myKey: [{ {
a: ''/span>,
b: [''/span>]。
c: [''/span>, ''/span>]。
}, {
a: '',
b: [''/span>]。
c: [''/span>, ''/span>]。
}]
}); // okay
check({
myKey: [{ /* error!
~~~~~ <--屬性'a'的型別不兼容。*/
a: ['']。
}, {
a: '',
}]
})
check({
myKey: [{ /* error!
~~~~~ <-- 屬性'd'在型別上不存在...。*/
a: ''。
b: [''/span>]。
c: [''/span>, ''/span>]。
}, {
a: '',
b: [''/span>]。
c: [''/span>, ''/span>]。
d: [""].
}]
})
check({
myKey: [{ /* error!
~~~~~ <-- 屬性'b'在型別中丟失...。*/
a: ['']。
b: ''a: [''/span>] 。
}]
})
我對它的唯一問題是,錯誤出現在一個稍微奇怪的地方。 不過,這或多或少是你的版本的直接延伸。
另一種方法是退一步,讓arg成為一個單一的引數型別T,然后想出一些約束條件,走過T的屬性,確保它們符合你的規則。 這對編譯器來說更容易推斷,因為你只是要求給出T型別的值,而不是給出T1和T2型別的值{[K in keyof T1]: [T1[K], ...T2[K][] ] 。}。 這里是:
//give names to types used more than once。
type StringBag = Record<string, string | readonly string[]> 。
型別 StringBagArray = readonly [StringBag, ...StringBag[] ] 。
type StrictCheckSubsequentProperties<T extends StringBagArray> ={
[I in keyof T] 。T[0] & {
[K in keyof T[I]] 。K extends keyof T[0] ? T[I][K] : 'TypeWithStrictPropertyCheck'] ?
}
};
export const check = <T extends { [K in keyof T] 。
StringBagArray & StrictCheckSubsequentProperties<T[K]>
}>(arg: T) =>arg;
這通過檢查arg中的每個屬性是否是StringBagArray(一個屬性為string或string[]的物件陣列)以及該陣列的所有元素是否可分配給第一個元素的型別。并且任何額外的鍵都是'TypeWithStrictPropertyCheck'的型別(我們也可以寫成never或者其他的東西)。
而且它也可以作業:
check( {
myKey: [{ {
a: ''/span>,
b: [''/span>]。
c: [''/span>, ''/span>]。
}, {
a: '',
b: [''/span>]。
c: [''/span>, ''/span>]。
}]
}) // ok
check({
myKey: [{ {
a: [''/span>]。
}, {
a: '', /* error!
~ <-- 'string'型別不能賦值給'string[]'型別 */。
}]
})
check({
myKey: [{ {
a: ''/span>,
b: [''/span>]。
c: [''/span>, ''/span>]。
}, {
a: '',
b: [''/span>]。
c: [''/span>, ''/span>]。
d: [""/span>] /* error!
~ <-- string[] 不能賦值給 "TypeWithStrictPropertyCheck" */。
}]
})
check({
myKey: [{ {
a: [''/span>]。
b: ''
}, { //error!
a: [''] 。
}] /*
~~~~~~~~~~~~~~~~~~~ <-- 屬性'b'在型別中丟失...
*/
})
我更喜歡這個版本中的錯誤位置,它更傾向于對問題所在的地方進行定位。 但最終還是要由你來決定哪個版本(如果有的話)能滿足你的需求。
轉載請註明出處,本文鏈接:https://www.uj5u.com/ruanti/322419.html
標籤:
