如操場所示,我有兩個函式“noneIs”和“someIs”,它們檢查給定陣列中的任何一項或某一項是否屬于特定型別。
重要的是要注意 !someIs(arr, type) == noneIs(arr, type) 當使用 !someIs 型別時沒有正確推斷,有人可以提出解決這個問題的方法嗎?
打字稿游樂場
uj5u.com熱心網友回復:
像這樣的東西對你有用嗎?...
type A = {type: "a", i: number};
type B = {type: "b", someOtherProp: string};
type C = {type: "c", i: number};
type Union = A | B | C;
// returns true if no item in array "arr" is of type "type"
const noneIs =
<K extends Union["type"]>
(arr: Union[], type: K):
arr is Exclude<Union, Union & {type: K}>[] =>
!arr.some(v => v.type == type);
// returns true if some item in array "arr" is of type "type"
const someIs =
<K extends Union["type"]>
(arr: Union[], type: K) =>
!noneIs(arr, type);
// example array of Union types
const arr: Union[] = [
{type: "a", i: 1},
{type: "c", i: 2}
];
// this works as expected
if(noneIs(arr, "b")){
arr[0].i;
}
// Even this doesn't work
// if(!noneIs(arr, "b")){
// arr[0].i;
// arr[0].someOtherProp;
// }
// but this does not
if(!someIs(arr, "b")){
// arr[0].i // <---- Not working
(arr[0] as Exclude<Union, B>).i; // <--- Working, Explicit Type assertion to make it work
}
uj5u.com熱心網友回復:
我將重申我對您的問題的評論并舉一個例子來支持它:
即使您通知編譯器至少有一個陣列元素與型別匹配,編譯器仍然不知道是哪個元素,因此someIs謂詞無助于縮小陣列的范圍。您需要縮小單個元素的范圍以安全地使用它們(這與編譯器選項解決的相同原則有關noUncheckedIndexedAccess)。
TS游樂場
type A = {type: 'a', i: number};
type B = {type: 'b', someOtherProp: string};
type C = {type: 'c', i: number};
type Union = A | B | C;
// Refactor of your example
function noneAre <T extends Union['type'], A extends readonly Union[]>(
type: T,
arr: A,
): arr is { [K in keyof A]: Exclude<A[K], { type: T }> } {
return arr.every(v => v.type !== type);
}
// Narrow a single `Union` element to a specific type
function isType <
T extends Union['type'],
V extends Union,
>(type: T, value: V): value is V & { type: T } {
return value.type === type;
}
///// Examples:
const a: A = {type: 'a', i: 1};
const b: B = {type: 'b', someOtherProp: 'str'};
const c: C = {type: 'c', i: 1};
const arr = [a, c]; // (A | C)[]
if(noneAre('a', arr)) arr; // arr is C[]
if(noneAre('c', arr)) arr; // arr is A[]
const tuple = [a, c] as [A, C]; // [A, C]
if(noneAre('a', tuple)){
tuple; // tuple is [never, C]
tuple[0].i; /*
^
Property 'i' does not exist on type 'never'.(2339) */
tuple[1].i; // number
}
const arr2: Union[] = [b, a, c, c, a /* ... */];
if(isType('b', arr2[0])){
const [
first, // element at index 0 is B
second, // element at index 1 is Union
third, // element at index 2 is Union
// ...etc.
] = arr2;
}
// Alternatively
const [first] = arr2; // first is Union
if (isType('c', first)) {
first; // C
}
else if (isType('a', first)) {
first; // A
}
else {
first; // B
}
轉載請註明出處,本文鏈接:https://www.uj5u.com/ruanti/419268.html
標籤:
