我正在使用一个返回类型断言的函数来告诉TypScript源明确具有或不具有media属性.如果是SourceWithoutMedia,则应该以一种方式处理,如果是SourceWithMedia,则应该以不同的方式处理.

问题在于TypScript从类型判定返回假的情况中推断出什么.

我预计TypScript会推断如果isSourceWithoutMedia(source)返回假,那么source就是SourceWithMedia.

它实际上推断的是,如果isSourceWithoutMedia(source)返回假,那么source的类型就是never.

我在这里错过了什么?有没有方法可以让TypScript推断如果isSourceWithoutMedia(source)返回假,那么source就是SourceWithMedia

interface SourceWithMedia {
    id: string
    someOtherProperty: string
    media?: string
}

interface SourceWithoutMedia {
    id: string
}

const isSourceWithoutMedia = (source: SourceWithMedia | SourceWithoutMedia): source is SourceWithoutMedia => {
    return Object.keys(source).length === 1
}

function doSomethingWithMedia (source: SourceWithMedia | SourceWithoutMedia) {
    if (isSourceWithoutMedia(source)) return source
    
    if (source.media) return source.media // Error: Property 'media' does not exist on type 'never'.
    
}

Example on TypeScript playground

推荐答案

...如果isSource WithoutMedia(source)返回False,则source是 Source WithMedia?

问题是SourceWithMedia延伸SourceWithoutMedia i.e. SourceWithMediaSourceWithoutMedia的亚型.

const withMedia: SourceWithMedia = {id: "", someOtherProperty: "", media: ""}
const withoutMedia = withMedia; // valid

当try 使用该动词将source缩小到SourceWithoutMedia时,实际上什么也没发生.source仍然具有联合类型,即使您在断言中使用类似!("media" in source)的内容或首先判断是否缺少media参数,这样:

function doSomethingWithMedia(source: SourceWithMedia | SourceWithoutMedia) {
  if (isSourceWithoutMedia(source)) {
    source;
    //^? (parameter) source: SourceWithMedia | SourceWithoutMedia
  }
}

现在,如果我们遵循if声明的负面分支,就没有任何unions 成员可以缩小范围.TypScript表示具有never类型的空联合.


另一方面,如果您invert您的断言逻辑并判断media属性是否显式存在,则您将能够将source缩小到SourceWithMedia.这样,TypScript实际上可以区分这两种类型,并告诉我们正在处理类型SourceWithMedia的值,因为SourceWithoutMedia不能赋给SourceWithMedia.

TypeScript Playground

Typescript相关问答推荐

在角形加载组件之前无法获取最新令牌

如何根据参数的值缩小函数内的签名范围?

对于使用另一个对象键和值类型的对象使用TS Generics

有没有办法解决这个问题,类型和IntrinsicAttributes类型没有相同的属性?

有条件地删除区分的联合类型中的属性的可选属性

如何调整对象 struct 复杂的脚本函数的泛型类型?

有没有可能为这样的函数写一个类型?

TypeError:正文不可用-NextJS服务器操作POST

是否将自动导入样式从`~/目录/文件`改为`@/目录/文件`?

如何在Vue中使用Enum作为传递属性的键类型?

转换器不需要的类型交集

带投掷的收窄类型

如何通过属性名在两个泛型数组中找到匹配的对象?

回调函数中的TypeScrip类型保护返回Incorect类型保护(具有其他未定义类型的返回保护类型)

KeyOf关键字在特定示例中是如何工作的

如何调整项目数组,但允许权重影响顺序

更漂亮的格式数组<;T>;到T[]

如何正确键入泛型相对记录值类型?

带有 Select 器和映射器的Typescript 泛型

如何判断路由或其嵌套路由是否处于活动状态?