如何在打字稿中将对象强制转换为其派生接口

时间:2020-03-08 12:30:38

标签: typescript

我正在尝试将对象(Item接口)投射到其派生接口(FileItem或FolderItem)

interface Item {
id: number;
name: string;
}

interface FileItem extends Item {
 size: number;
}

interface FolderItem extends Item {
  parent_id: number;
}

const files: FileItem[] = [ {id: 1, name: 'file name 1', size: 1024 } ];
const folders: FolderItem[] = [ {id:1, name: 'folder 1', parent_id: 0} ];
const items = new Array<Item>(...files, ...folders);
items.forEach(i => {
  const isFile = i as FileItem;
  if (isFile) {
   writeLog('its a file');
 }
 else writeLog('its a folder');
})

在foreach循环中,打字稿将所有项目都强制转换为FileItem,这是错误的,因为它应该强制转换为FileItem和FolderItem,请查看demo
这是打字稿中的类型转换的工作方式吗?如何转换为正确的界面。
谢谢

1 个答案:

答案 0 :(得分:0)

这不是Typescript中的类型转换的工作方式。在编译期间,所有类型都被剥离,因此您的代码将最终如下所示:

const files = [ {id: 1, name: 'file name 1', size: 1024 } ];
const folders = [ {id:1, name: 'folder 1', parent_id: 0} ];
const items = new Array(...files, ...folders);
items.forEach(i => {
  const isFile = i;
  if (isFile) {
   writeLog('its a file');
 }
 else writeLog('its a folder');
})

isFile永远是真实的,因为i是真实的。

要获得所需的服务,您需要使用type guard。例如:

function isFile(item: Item): item is FileItem {
  return (item as FileItem).size !== undefined;
}

这将检查Item是否具有属性size。如果是,则必须为FileItem。您可以这样使用它:

items.forEach(i => {
  if (isFile(i)) {
    writeLog('its a file');
  }
  else writeLog('its a folder');
})

完整代码:

interface Item {
  id: number;
  name: string;
}

interface FileItem extends Item {
  size: number;
}

interface FolderItem extends Item {
  parent_id: number;
}

function isFile(item: Item): item is FileItem {
  return (item as FileItem).size !== undefined;
}

const files: FileItem[] = [ {id: 1, name: 'file name 1', size: 1024 } ];
const folders: FolderItem[] = [ {id:1, name: 'folder 1', parent_id: 0} ];
const items = new Array<Item>(...files, ...folders);
items.forEach(i => {
  if (isFile(i)) {
   writeLog('its a file');
 }
 else writeLog('its a folder');
})

此外,您为什么使用new Array?您可以这样做:

const items: Item[] = [...files, ...folders]