interface Test<T> {
field: string | T;
}
function isString<T>(test: Test<T>): test is Test<string> {
return typeof test.field === "string";
}
function f<T>(test: Test<T>) {
if (isString(test)) {
const a = test.field; // the type of a is string
} else {
const b = test.field; // the type of b is string | T
}
}
在上面的代码中,在if
分支上,a
的类型为string
,这是正确的。但是,在else
分支上,b
的类型为string | T
。
即使我添加T
的支票,我也会得到相同的结果:
function isT<T>(test: Test<T>): test is Test<T> {
return typeof test.field !== "string";
}
function f<T>(test: Test<T>) {
if (isString(test)) {
const a = test.field; // the type of a is string
} else if (isT(test)) {
const b = test.field; // the type of b is string | T
}
}
我不能明确地将b
投射到T
,就像我不需要将a
投射到string
一样?
答案 0 :(得分:1)
问题是user-defined type guard正在检查Test<T>
的类型,但您想要的是field
的类型。
您的分支看起来像这样:
function f<T>(test: Test<T>) {
if (isString(test)) {
// We have a `Test<string>`
const a = test.field;
} else {
// We do not have a `Test<string>`
const b = test.field;
}
}
在if
分支中,我们有Test<string>
,其field
属性是string | string
的联合(只是string
)。类型如下:
interface Test<string> {
field: string | string;
}
在else
分支中,我们有Test<SomeNonString>
,其field
属性是string | SomeNonString
的联合。它的类型如下:
interface Test<SomeNonString> {
field: string | SomeNonString;
}
在else
分支中,我们需要消除歧义,因为field
仍然是联合类型。只要Test<T>
接口将field
定义为string | T
的联合类型,我们就需要在T
不是string
时进行后续测试。
以下是一个例子:
function isFieldString<T>(field: string | T): field is string {
return typeof field === "string";
}
function f<T>(test: Test<T>) {
if (isString(test)) {
const s = test.field; // const s: string
} else if (isFieldString(test.field)) {
const s = test.field; // const s: string
} else {
const t = test.field; // const t: T
}
}