Typescript缩小到相同类型将缩小到从不

Typescript缩小到相同类型将缩小到从不,typescript,type-narrowing,Typescript,Type Narrowing,我遇到了这个类型脚本错误 Property 'id' does not exist on type 'never'. 我在这里制作了一个简化的示例() 真正的代码更复杂,但本质上,我认为问题在于上面的两个接口是相同的。如果我向Get接口添加一个假字段,使它们不同,那么错误就会消失。我正在努力寻找关于这里到底发生了什么以及如何修复或解决它的文档。添加一个假字段是很麻烦的,我真的不想将Get和Delete组合成一个共享类型,除非没有其他方法。Get和Delete接口是一样的。TypeScript有

我遇到了这个类型脚本错误

Property 'id' does not exist on type 'never'.
我在这里制作了一个简化的示例()


真正的代码更复杂,但本质上,我认为问题在于上面的两个接口是相同的。如果我向
Get
接口添加一个假字段,使它们不同,那么错误就会消失。我正在努力寻找关于这里到底发生了什么以及如何修复或解决它的文档。添加一个假字段是很麻烦的,我真的不想将
Get
Delete
组合成一个共享类型,除非没有其他方法。

Get
Delete
接口是一样的。TypeScript有一种称为duck typing的东西,所以在您检查了if
nerrowme
comforms to
Get
interface之后,TS知道它也可以comforms to
Delete
interface,所以您的第二个
if
实际上是不可能的。这类问题通常通过判别式解决:

interface Get {
  type: 'get';
  id: number;
}
interface Delete {
  type: 'delete';
  id: number;
}
我同意它看起来确实很粗糙,但这只是打字脚本类型系统的一个特性。如果两个接口相同,则它们描述相同的可能对象集。他们的名字并不重要,你必须以其他方式区别对待他们

interface Get {
  type: 'get';
  id: number;
}
interface Delete {
  type: 'delete';
  id: number;
}

const isGet = (narrowMe: Get | Delete): narrowMe is Get =>
  narrowMe.type === "get";
const isDel = (narrowMe: Get | Delete): narrowMe is Delete =>
  narrowMe.type === "delete";

const foo = (narrowMe: Get | Delete, narrowBy: string) => {
  if (isGet(narrowMe)) {
    return narrowMe.id;
  } else if (isDel(narrowMe)) {
    return narrowMe.id; // no error, narrowMe is of type Delete
  }
};

Get
Delete
接口是一样的。TypeScript有一种称为duck typing的东西,所以在您检查了if
nerrowme
comforms to
Get
interface之后,TS知道它也可以comforms to
Delete
interface,所以您的第二个
if
实际上是不可能的。这类问题通常通过判别式解决:

interface Get {
  type: 'get';
  id: number;
}
interface Delete {
  type: 'delete';
  id: number;
}
我同意它看起来确实很粗糙,但这只是打字脚本类型系统的一个特性。如果两个接口相同,则它们描述相同的可能对象集。他们的名字并不重要,你必须以其他方式区别对待他们

interface Get {
  type: 'get';
  id: number;
}
interface Delete {
  type: 'delete';
  id: number;
}

const isGet = (narrowMe: Get | Delete): narrowMe is Get =>
  narrowMe.type === "get";
const isDel = (narrowMe: Get | Delete): narrowMe is Delete =>
  narrowMe.type === "delete";

const foo = (narrowMe: Get | Delete, narrowBy: string) => {
  if (isGet(narrowMe)) {
    return narrowMe.id;
  } else if (isDel(narrowMe)) {
    return narrowMe.id; // no error, narrowMe is of type Delete
  }
};

问题是,以这种方式使用类型保护并不是它们的本意,因此将以意外的方式进行操作

最简单的解决方案不是基于类型guards,而是基于窄比变量:

interface Get {
    id: number;
}
interface Delete {
    id: number;
}

const isGet = (narrowMe: Get | Delete, narrowBy: string): narrowMe is Get =>
    narrowBy === "GET";
const isDel = (narrowMe: Get | Delete, narrowBy: string): narrowMe is Delete =>
    narrowBy === "DELETE";

function foo(narrowMe: Get | Delete, narrowBy: string): number {
    switch (narrowBy) {
        case "GET":
        case "DELETE":
            return narrowMe.id;
        default:
            throw new Error(`Invalid parameter narrowBy, expected "GET" or "DELETE" but got ${narrowBy}`);
    }

};

问题在于,以这种方式使用类型防护并不是它们的本意,因此会以意外的方式运行

最简单的解决方案不是基于类型guards,而是基于窄比变量:

interface Get {
    id: number;
}
interface Delete {
    id: number;
}

const isGet = (narrowMe: Get | Delete, narrowBy: string): narrowMe is Get =>
    narrowBy === "GET";
const isDel = (narrowMe: Get | Delete, narrowBy: string): narrowMe is Delete =>
    narrowBy === "DELETE";

function foo(narrowMe: Get | Delete, narrowBy: string): number {
    switch (narrowBy) {
        case "GET":
        case "DELETE":
            return narrowMe.id;
        default:
            throw new Error(`Invalid parameter narrowBy, expected "GET" or "DELETE" but got ${narrowBy}`);
    }

};

我想知道在我的情况下,我是否应该以不同的方式来处理这个问题,因为我正试图通过一个不同的参数
窄比
来缩小
窄比。如果可能的话,这就是第二个的原因。尽管
窄域
是相同的,
窄域
可以不同。当然可以,但是
窄域
必须与接口连接。恐怕你得用鉴别器。。。请参见编辑。为什么必须将
窄比
与接口连接?基于类型B的值来缩小类型A是否不公平?我想知道在我的情况下,我是否应该以不同的方式来处理这个问题,因为我正试图通过不同的参数来缩小
窄比
。如果可能的话,这就是第二个的原因。尽管
窄域
是相同的,
窄域
可以不同。当然可以,但是
窄域
必须与接口连接。恐怕你得用鉴别器。。。请参见编辑。为什么必须将
窄比
与接口连接?根据B类的价值缩小A类的范围是否不公平?