![](/img/trans.png)
[英]How to declare a specific type of empty array inside a object using typescript?
[英]An array of object with specific type using generics with typescript
我想要一個以下類型的對象數組(任意長度):
[
{p1: T, p2: T},
{p1: T2, p2: T2}
...
]
對於單個對象,這可以按我的意願工作:
type O<T> = {
p1: T;
p2: T;
};
const f = <T,>(a: O<T>) => {
console.log(a)
}
f({ p1: 1, p2: 2 }); // makes sure p1 and p2 has the same type
我想將對象數組傳遞給函數f
,並且我希望每個對象單獨具有相同的類型約束。
我試過了:
O<T> = {
p1: T;
p2: T;
}
const f = <T,>(a: O<T>[]) => {
console.log(a)
}
f([
{ p1: 1, p2: 2 },
{ p1: '3', p2: '4' }, // Type 'string' is not assignable to type 'number'
]);
我也試過:
type O<T> = {
p1: T;
p2: T;
};
type A<T> = {
[P in keyof T]: O<T[P]>;
};
const f = <T,>(a: A<T>) => {
console.log(a)
}
f([
{ p1: 1, p2: 2 },
{ p1: 3, p2: '4' }, // allows but I don't want it to be allowed p1 != p2 unfortunatly T resolvs to string | number
]);
我希望O<T>
分別應用於數組中的每個對象。 我嘗試了很多東西,在這一點上我不確定是否可以使用打字稿來實現這一點。
我希望這適用於任何自定義類型,而不僅僅是number | string
number | string
。
任何幫助將非常感激。
為此,我們需要從列表中推斷每個元素並檢查p1
和p2
是否具有相同的類型。
要從列表中推斷每個元素,我們需要使用可變元組類型。 除此之外,我們需要遍歷每個元素並檢查p1
和p2
。
看到這個:
type BothEqual<T extends Base<any>> =
T['p1'] extends T['p2']
? (T['p2'] extends T['p1']
? T
: never)
: never
type Validation<
Arr extends Array<unknown>,
Result extends Array<unknown> = []
> =
Arr extends []
? []
: (Arr extends [infer H extends Base<any>]
? [...Result, BothEqual<H>]
: (Arr extends [infer Head extends Base<any>, ...infer Tail]
? Validation<[...Tail], [...Result, BothEqual<Head>]>
: Readonly<Result>)
)
BothEqual
只是檢查p1
和p2
是否具有相同的類型。
Validation
- 遍歷列表中的 eack 元素並在其上調用BothEqual
。 因此,如果 elem 有效,則返回此元素,否則返回never
:
interface Base<T> {
p1: T,
p2: T
};
type BothEqual<T extends Base<any>> =
T['p1'] extends T['p2']
? (T['p2'] extends T['p1']
? T
: never)
: never
type Validation<
Arr extends Array<unknown>,
Result extends Array<unknown> = []
> =
/**
* If Arr is empty tuple, return empty result
*/
Arr extends []
? []
/**
* If Arr is a tuple with one element, stop recursion.
* See TS 4.7 https://devblogs.microsoft.com/typescript/announcing-typescript-4-7/#extends-constraints-on-infer-type-variables docs
* for [infer H extends Base<any>] syntax
*
*/
: (Arr extends [infer H extends Base<any>]
? [...Result, BothEqual<H>]
/**
* If Arr has more than one element - call it recursively
*/
: (Arr extends [infer Head extends Base<any>, ...infer Tail]
? Validation<[...Tail], [...Result, BothEqual<Head>]>
: Readonly<Result>)
)
function f<T, List extends Base<T>[]>(a: [...List] & Validation<[...List]>) {
console.log(a)
}
f([
{ p1: 1, p2: 2 },
{ p1: 3, p2: '42' } // error
]);
Playground您可能已經注意到,提供的參數中的第二個元素被突出顯示。 此外,您可以將p1
優先於p2
。 這意味着p1
是真實的來源。 然后,如果p2
無效,則僅突出顯示p2
。 嘗試這個:
type BothEqual<T extends Base<any>> =
T['p2'] extends T['p1']
? T
: Omit<T, 'p2'> & { p2: never }
您可以簡化Validation
類型:
type Validation<
Arr extends Array<unknown>,
> =
{
[Elem in keyof Arr]: Arr[Elem] extends Base<any> ? BothEqual<Arr[Elem]> : never
}
但是隨后數組中的所有元素都將突出顯示,這可能很難理解出了什么問題。
如果您對 TS 函數參數驗證和元組迭代感興趣,可以查看我博客中的這些文章:
我想你一開始就擁有它;-)
type O<T1, T2> = [ { p1: T1, p2: T1 }, { p3: T2, p4: T2 } ]
function f<T1,T2>(a: O<T1, T2>) {
console.log(a)
}
f([
{ p1: 1, p2: 2 },
{ p3: '3', p4: '4' }
]);
f<number, string>([
{ p1: 1, p2: 2 },
{ p3: '3', p4: '4' }
]);
f<number, string>([
{ p1: 1, p2: 2 },
{ p3: 3, p4: '4' }
//^^ Type 'number' is not assignable to type 'string'
]);
在沒有顯式類型的情況下對{p3: 3, p4: '4'}
進行正確警告的部分問題是,泛型f
根據輸入參數推斷類型。 它告訴您第二個對象不能有不匹配的類型,但它們可能與第一個對象類型相同( T1
和T2
可以合法地是相同的類型)。
您可以使泛型有條件,以便T2
不能擴展T1
但這可能會限制對象而不知道它們的形狀。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.