>我正在尝试以下代码,但不确定我是否可以告诉打字稿从任一接口假定类型
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
可以是没有属性date
的CellA
类型(因此您会收到错误消息)。请注意,反之亦然,cell
也没有属性text
。
潜在解决方案
1. 使用交集类型
如果cell
应该是CellA
和CellB
的组合,那么您可以制作类型CellA & CellB
的cell
。例如:
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非常相似。如果CellA
和CellB
应该共享一些属性,那么其中一个可以扩展另一个,或者它们可以扩展一个公共接口。例如:
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
分配为CellA
或CellB
类型时,打字稿会抱怨,因为每种类型都缺少其中一个属性。
您可以只分配可选属性吗? 喜欢这个:
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;
}
}
编译器将此模式理解为基于运行时类型进行调度,但它仍将提供编译时类型安全性,因为不能只传递不符合的值。
操场