如何在打字稿中添加多个断言



>我正在尝试以下代码,但不确定我是否可以告诉打字稿从任一接口假定类型

export interface CellA {
text: string;
}
export interface CellB {
date: Date;
}
var cell = {};
const { date, text } = cell as (CellA | CellB);
console.log(date, text);

TS 错误:类型"单元格 | 单元格B'。(2339)

我想要的是让打字稿假设析构的变量存在于任何一个接口中。TS 操场示例

您的问题是cell可以是没有属性dateCellA类型(因此您会收到错误消息)。请注意,反之亦然,cell也没有属性text

潜在解决方案

1. 使用交集类型

如果cell应该是CellACellB的组合,那么您可以制作类型CellA & CellBcell。例如:

type CellC = CellA & CellB
const cell: CellC = { date: new Date(), text: 'Hello!' }
const { date, text }
console.log(date, text)

2.使用类型防护装置:游乐场

如果有需要在运行时进行类型检查的值,则可以使用用户定义的类型保护。例如,如果您有一个变量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非常相似。如果CellACellB应该共享一些属性,那么其中一个可以扩展另一个,或者它们可以扩展一个公共接口。例如:

interface Cell {
date: Date
}
interface CellC extends Cell {
text: string
}

4:反应组件组成

如果您特别遇到此问题 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组件共享公共逻辑。

你这样做的方式是假设cell既有date又有text。 但是,当您将cell分配为CellACellB类型时,打字稿会抱怨,因为每种类型都缺少其中一个属性。

您可以只分配可选属性吗? 喜欢这个:

interface CellType {
date?: Date,
text?: string
}
const { date, text } = cell as CellType

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

interface CellA {
text: string;
}
interface CellB {
date: Date;
}
type CellType = CellA | CellB
const cell: CellType = { ... }

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

export interface CellA {
text?: string;
[index: string]: any;
}
export interface CellB {
date?: Date;
[index: string]: any;
}

通常,如果要在 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;
}
}

编译器将此模式理解为基于运行时类型进行调度,但它仍将提供编译时类型安全性,因为不能只传递不符合的值。

操场

最新更新