Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/visual-studio-code/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Typescript:如何使用具有结构而不是具有鉴别属性的鉴别并集?_Typescript_Visual Studio Code - Fatal编程技术网

Typescript:如何使用具有结构而不是具有鉴别属性的鉴别并集?

Typescript:如何使用具有结构而不是具有鉴别属性的鉴别并集?,typescript,visual-studio-code,Typescript,Visual Studio Code,我想写一个函数从源文件中检索文件内容。源文件只有两种结构。我想使用with来处理内容 我需要,所以我打开了strictNullChecks。我希望,如果它成功地创建了有区别的联合,编译器不会将| undefined添加到函数retrieveFileContent中返回的fileContent。但是Typescript编译器抛出一个错误: error TS2322: Type '{ type: FileContentType; payload: string; } | { type: FileCo

我想写一个函数从源文件中检索文件内容。源文件只有两种结构。我想使用with来处理内容

我需要,所以我打开了
strictNullChecks
。我希望,如果它成功地创建了有区别的联合,编译器不会将
| undefined
添加到函数
retrieveFileContent
中返回的
fileContent
。但是Typescript编译器抛出一个错误:

error TS2322: Type '{ type: FileContentType; payload: string; } | { type: FileContentType; payload: { filename: string; path: string; }; } | undefined' is not assignable to type 'FileContent'.
Type 'undefined' is not assignable to type 'FileContent'
如何修改代码以使用用户定义的类型保护权限进行区分联合?或者对于我的用例还有其他更好的解决方案吗

Sorce代码:

// Target File Content Format

enum FileContentType {
  disk,
  memory,
}

interface FileContentInMemory {
  type: FileContentType.memory
  payload: string
}

interface FileContentInDisk {
  type: FileContentType.disk
  payload: {
    filename: string
    path: string
  }
}

type FileContent = FileContentInMemory | FileContentInDisk

// Source File Containing Content

interface FileBasics {
  fieldname: string
  originalname: string
  encoding: string
  mimetype: string
  size: number
}

interface FileInMemory extends FileBasics {
  fileString: string
}

interface FileInDisk extends FileBasics {
  filePath: string
}

type SourceFile = FileInMemory | FileInDisk

function isInMemory(file: SourceFile): file is FileInMemory {
  return (<FileInMemory>file).fileString !== undefined
}

function isInDisk(file: SourceFile): file is FileInDisk {
  return (<FileInDisk>file).filePath !== undefined
}

// Retrieve Content From File

function retrieveFileContent(file: SourceFile): FileContent {
  let fileContent
  if (isInMemory(file)) {
    fileContent = {
      type: FileContentType.memory,
      payload: file.fileString
    }
  } else if (isInDisk(file)) {
    fileContent = {
      type: FileContentType.disk,
      payload: {
        filename: file.originalname,
        path: file.filePath,
      }
    }
  }
  return fileContent
}

据我所知,这种类型的穷尽性检查仅适用于:

您正在执行的检查并不真正适合于
开关
语句。幸运的是,您可以使用中列出的第二种穷尽性检查方法:在所有检查完成后,如果
文件
未缩小到
从不
,则使用帮助函数引发编译器错误:

function assertNever(x: never): never {
  throw new Error("Unexpected object: " + x);
}

function retrieveFileContent(file: SourceFile): FileContent {
  let fileContent: FileContent; // use annotation to avoid any
  if (isInMemory(file)) {
    fileContent = {
      type: FileContentType.memory,
      payload: file.fileString
    }
  } else if (isInDisk(file)) {
    fileContent = {
      type: FileContentType.disk,
      payload: {
        filename: file.originalname,
        path: file.filePath,
      }
    }
  } else return assertNever(file); // no error, file is never      
  return fileContent; // no error, fileContent is FileContent
}

希望有帮助。祝你好运

我使用
typescript@3.0.1
我认为函数
ifVersion
可以工作,因为它的逻辑与
switchVersion
相同。但现在我知道,正如你所指出的,它将被打破。您的解决方案非常有效!谢谢!
type DiscriminatedUnion = {k: "Zero", a: string} | {k: "One", b: string};

// works
function switchVersion(d: DiscriminatedUnion): string {
  switch (d.k) {
    case "Zero": return d.a;
    case "One": return d.b;
  }
}

// broken
function ifVersion(d: DiscriminatedUnion): string {
// Error! might not return a string -----> ~~~~~~  
  if (d.k === "Zero") return d.a;
  if (d.k === "One") return d.b;  
}
function assertNever(x: never): never {
  throw new Error("Unexpected object: " + x);
}

function retrieveFileContent(file: SourceFile): FileContent {
  let fileContent: FileContent; // use annotation to avoid any
  if (isInMemory(file)) {
    fileContent = {
      type: FileContentType.memory,
      payload: file.fileString
    }
  } else if (isInDisk(file)) {
    fileContent = {
      type: FileContentType.disk,
      payload: {
        filename: file.originalname,
        path: file.filePath,
      }
    }
  } else return assertNever(file); // no error, file is never      
  return fileContent; // no error, fileContent is FileContent
}