我可以轻松地使用常量字符串值来缩小联合类型的范围:
type Payload1 = { /* ... arbitrary type ... */ };
type Payload2 = { /* ... arbitrary type ... */ };
type T1 = { type: 'type1', payload: Payload1 }
type T2 = { type: 'type2', payload: Payload2 }
type T = T1 | T2;
const fn = (value: T) => {
if (value.type === 'type1') {
value; // Typescript knows `value is T1`
}
if (value.type === 'type2') {
value; // Typescript knows `value is T2`
}
};
这里只有两种情况:
-
value.type
是常量"type1"
-
value.type
是常量"type2"
但是,如果我扩展T
,允许payload
既可以是单个项,也可以是一个数组,会怎么样呢?现在有4种可能性:
-
value.type
是"type1"
,value.payload
是not和array
-
value.type
是"type1"
,value.payload
is是array
-
value.type
是"type2"
,value.payload
是not和array
-
value.type
是"type2"
,value.payload
is是array
下面是一个例子:
type Payload1 = {};
type Payload2 = {};
type T1Single = { type: 'type1', payload: Payload1 }
type T1Batch = { type: 'type1', payload: Payload1[] };
type T2Single = { type: 'type2', payload: Payload2 }
type T2Batch = { type: 'type2', payload: Payload2[] };
// Here's T, now with 4 types instead of 2:
type T = T1Single | T1Batch | T2Single | T2Batch;
const fn = (value: T) => {
if (value.type === 'type1' && !Array.isArray(value.payload)) {
value; // Typescript says `value is T1Single | T1Batch`?!
// How does `T1Batch` remain in the union if `value.payload` isn't an array??
}
if (value.type === 'type1' && Array.isArray(value.payload)) {
value; // Typescript says `value is T1Single | T1Batch`?!
// How does `T1Single` remain in the union if `value.payload` is an array??
}
if (value.type === 'type2' && !Array.isArray(value.payload)) {
value; // Typescript says `value is T2Single | T2Batch`?!
// How does `T2Batch` remain in the union if `value.payload` isn't an array??
}
if (value.type === 'type2' && Array.isArray(value.payload)) {
value; // Typescript says `value is T2Single | T2Batch`?!
// How does `T2Single` remain in the union if `value.payload` is an array??
}
};
Why is typescript only partially narrowing down the type, and how can I achieve fully narrowed values for the 4 cases?个
编辑:看起来if
个条件中的多个条件无关紧要;仅凭Array.isArray
个字就很难缩小范围:
type Payload = {};
type Single = { payload: Payload }
type Batch = { payload: Payload[] };
const fn = (value: Single | Batch) => {
if (!Array.isArray(value.payload)) {
value; // Typescript says `value is Single | Batch`?!
}
if (Array.isArray(value.payload)) {
value; // Typescript says `value is Single | Batch`?!
}
};