为了账号安全,请及时绑定邮箱和手机立即绑定

如何在 Typescript 中添加多个断言

如何在 Typescript 中添加多个断言

当年话下 2023-07-06 17:01:03
我正在尝试下面的代码,不确定是否可以告诉打字稿从任一接口假定类型export interface CellA {    text: string;}export interface CellB {    date: Date;}var cell = {};const { date, text } = cell as (CellA | CellB);console.log(date, text);TS 错误:类型“CellA | ”上不存在属性“日期” 细胞B'。(2339)我所追求的是让打字稿假设被破坏的变量存在于任一接口中。
查看完整描述

4 回答

?
炎炎设计

TA贡献1808条经验 获得超4个赞

您的问题是,它cell的类型可能CellA不具有该属性date(因此您收到的错误消息)。请注意,反之亦然,即cell也不具有该属性text。


潜在的解决方案

1.使用交叉类型

如果cell应该是两者的组合CellA,CellB那么你可以制作celltype CellA & CellB。例如:


type CellC = CellA & CellB


const cell: CellC = { date: new Date(), text: 'Hello!' }


const { date, text }

console.log(date, text)

2.使用类型守卫:Playground

如果您有一个值需要在运行时进行类型检查,则可以使用用户定义的类型保护。例如,如果您有一个cell在运行时不知道其类型的变量:

const cell = { text: 'Hello!' } // unknown type


function isCellA(obj: any): obj is CellA {

    if(!obj) return false

    if(!obj.text) return false

    if(typeof obj.text !== 'string') return false


    return true

}


if(isCellA(cell)) {

    // at this point the compiler recognizes that cell

    // is of type CellA

    console.log(cell.text)

}

如果您需要在运行时进行类型检查,这可能是您的最佳选择。它可以维护类型安全,并有助于减少运行时错误(如果cell确实不是您所期望的那样)。


3.扩展另一个接口

这与解决方案#1 非常相似。如果CellA和CellB应该共享一些属性,那么它们之一可以扩展另一个,或者它们可以扩展一个公共接口。例如:


interface Cell {

    date: Date

}


interface CellC extends Cell {

    text: string

}

4:React组件组成

如果您特别遇到此问题,React(如您的评论所述),您可以考虑使用一个单独的组件来返回每种单元格类型的主要组件。例子:


function ACell({ data }: { data: CellA } ) {

    return <Cell>{data.text}<Cell>

}


function BCell({ data }: { data: CellB } ) {

    return <Cell>{data.date.toString()}<Cell>

}


function Cell({ children }: { children: string }) {

    return <p>{children}</p>

}

也许这不符合您的特定用例,但类似的东西可能有助于分离组件之间每种类型单元的逻辑,以及Cell例如与第三个组件共享公共逻辑。


查看完整回答
反对 回复 2023-07-06
?
茅侃侃

TA贡献1842条经验 获得超21个赞

您这样做的方式是做出cell同时具有date和text的假设。但是,当您指定cell为 aCellA或CellB类型时,打字稿会抱怨,因为每种类型都缺少其中一个属性。


您可以只分配可选属性吗?像这样:


interface CellType {

  date?: Date,

  text?: string

}


const { date, text } = cell as CellType

或者,如果您确实想强制 acell严格成为这些类型之一,我会在定义变量时执行此操作:


interface CellA {

  text: string;

}


interface CellB {

  date: Date;

}


type CellType = CellA | CellB


const cell: CellType = { ... }


查看完整回答
反对 回复 2023-07-06
?
慕村9548890

TA贡献1884条经验 获得超4个赞

通常,当您想要在 Typescript 中的参数/变量类型上切换控制流时,您需要使用可区分联合:


interface CellA {

  text: string,

  kind: "CellA",

}


interface CellB {

  date: Date,

  kind: "CellB",

}


type Cell = CellA | CellB;


function takesACell(cell: Cell) {

  switch(cell.kind) {

    case "CellA":

      console.log("Got an A");

      cell.text; // no type error

      break;

    case "CellB":

      console.log("Got a B");

      cell.date; // no type error

      break;

  }

}

编译器将这种模式理解为您正在根据运行时类型进行分派,但它仍然会提供编译时类型安全性,因为您不能只传递不合格的值。


查看完整回答
反对 回复 2023-07-06
?
饮歌长啸

TA贡献1951条经验 获得超3个赞

如果可能的话,您可以扩展接口以接受任何其他值。例如:


export interface CellA {

    text?: string;

    [index: string]: any;

}


export interface CellB {

    date?: Date;

    [index: string]: any;

}


查看完整回答
反对 回复 2023-07-06
  • 4 回答
  • 0 关注
  • 91 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信