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