Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/typescript/8.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 - Fatal编程技术网

Typescript 基于类内替换的扩展方法更改返回值

Typescript 基于类内替换的扩展方法更改返回值,typescript,Typescript,我有一个类FileHandler,然后是一个扩展原始类的FileOrNullHandler类 问题是FileOrNullHandler中从FileHandler继承的方法与原始类中编写的返回类型保持一致 export class FileHandler { static async readFileFromFileQuery (fq: FileQuery): Promise<File> { const { path, encoding, flag } = Fi

我有一个类
FileHandler
,然后是一个扩展原始类的
FileOrNullHandler

问题是
FileOrNullHandler
中从
FileHandler
继承的方法与原始类中编写的返回类型保持一致

export class FileHandler {
    static async readFileFromFileQuery (fq: FileQuery): Promise<File> {
        const { path, encoding, flag } = FileQueryHandler.make(fq);
        const content = await promisify(fs.readFile)(path, { encoding, flag })
        return { path, encoding, flag, content };
    }
    static async readFile (a: Path | FileQuery, b?: Omit<FileQuery, 'path'>): Promise<File> {
        if (typeof a === 'string') a = FileQueryHandler.getFromPath(a, b);
        return this.readFileFromFileQuery(a);
    }
    static async readFiles (a: (Path | FileQuery)[] | Directory, b?: Omit<FileQuery, 'path'>): Promise<File[]> {        
        if (a instanceof Array) return Promise.all(a.map(p => this.readFile(p, b)));
        return this.readFiles(PathHandler.getFromDirectory(a), b);
    }
    static async readFilesFromDirectory(a: Path | FileQuery, b?: Omit<FileQuery, 'path'>): Promise<File[]> {
        const ps = await DirectoryHandler.readDirectory(a);    
        if (typeof a === 'string') return await (this).readFiles(ps, b);
        return await this.readFiles(ps, a);
    }
}

export class FileOrNullHandler extends FileHandler {
    static async readFileFromFileQuery (fq: FileQuery): Promise<File | null> {
        return orNull(() => FileHandler.readFileFromFileQuery(fq));
    }
}
导出类文件处理程序{
静态异步readFileFromFileQuery(fq:FileQuery):承诺{
const{path,encoding,flag}=FileQueryHandler.make(fq);
const content=await promisify(fs.readFile)(路径,{encoding,flag})
返回{path,encoding,flag,content};
}
静态异步读取文件(a:Path | FileQuery,b?:省略):承诺{
if(typeof a=='string')a=FileQueryHandler.getFromPath(a,b);
返回此.readFileFromFileQuery(a);
}
静态异步读取文件(a:(路径|文件查询)[]|目录,b?:省略):承诺{
if(数组的instanceof)返回Promise.all(a.map(p=>this.readFile(p,b));
返回此.readFiles(PathHandler.getFromDirectory(a),b);
}
静态异步readFilesFromDirectory(a:Path | FileQuery,b?:省略):承诺{
const ps=await DirectoryHandler.readDirectory(a);
if(typeof a=='string')返回wait(this).readFiles(ps,b);
返回等待此.readFiles(ps,a);
}
}
导出类FileOrNullHandler扩展FileHandler{
静态异步readFileFromFileQuery(fq:FileQuery):承诺{
返回orNull(()=>FileHandler.readFileFromFileQuery(fq));
}
}
我在这里看到了获得正确类型的两个选项之一

  • 基于
    设置原始方法的相对返回类型。(可能不可能)
  • 覆盖
    FileOrNullHandler
    中的方法
    ReturnType

  • OOP的通用租户是派生类应该能够替换基类。在这种情况下,派生类无法替换基类,因为派生类具有基类的客户端不知道会期望的返回类型(
    null

    那家伙说我们可以接近你想要的

    首先,我不会使用只包含静态方法的类,我会创建一个包含实例方法的类,并声明该实例类型的
    const
    ,然后将其导出以供人们作为单例使用

    其次,我将移动公共基类中的公共功能,
    readFileFromFileQuery
    方法是抽象的,类是泛型的。这允许我们插入一个返回
    File
    的版本,或者一个返回
    File | null
    的版本,而不违反Typescript(和OOP)一致性规则

    最终的解决方案是这样的(我填写了一些类型,不确定它们的实际定义是什么,但我添加了代码无错误所需的最低限度的内容):

    抽象类\u FileHandlerBase{
    摘要readFileFromFileQuery(fq:FileQuery):承诺;
    异步读取文件(a:Path | FileQuery,b?:省略):承诺{
    if(typeof a=='string')a=FileQueryHandler.getFromPath(a,b);
    返回此.readFileFromFileQuery(a);
    }
    异步读取文件(a:(路径|文件查询)[]|目录,b?:省略):承诺{
    if(数组的instanceof)返回Promise.all(a.map(p=>this.readFile(p,b));
    返回此.readFiles(PathHandler.getFromDirectory(a),b);
    }
    异步readFilesFromDirectory(a:Path | FileQuery,b?:省略):承诺{
    const ps=await DirectoryHandler.readDirectory(a);
    if(typeof a=='string')返回wait(this).readFiles(ps,b);
    返回等待此.readFiles(ps,a);
    }
    }
    导出类_FileHandler扩展_FileHandlerBase{
    异步readFileFromFileQuery(fq:FileQuery):承诺{
    const{path,encoding,flag}=FileQueryHandler.make(fq);
    const content=await promisify(fs.readFile)(路径,{encoding,flag})
    返回{path,encoding,flag,content};
    }
    }
    export const FileHandler=new_FileHandler();
    导出类_FileOrNullHandler扩展_FileHandlerBase{
    异步readFileFromFileQuery(fq:FileQuery):承诺{
    返回orNull(()=>FileHandler.readFileFromFileQuery(fq));
    }
    }
    export const FileOrNullHandler=new_FileOrNullHandler();
    FileHandler.readFileFromFileQuery(null!)//承诺
    FileOrNullHandler.readFileFromFileQuery(null!)//承诺
    FileHandler.readFiles(null!)//承诺
    FileOrNullHandler.readFiles(null!)//承诺
    //一些假设
    类型路径=字符串;
    接口文件查询{
    路径:字符串,标志?:字符串,编码?:字符串|空
    }
    导出接口文件{
    路径:字符串,标志?:字符串,编码:字符串|未定义|空,内容:缓冲区|字符串
    }
    接口目录{
    路径:字符串,isDir:true
    }
    声明var FileQueryHandler:{
    make(fq:FileQuery):FileQuery
    getFromPath(s:string,b?:省略):FileQuery;
    }
    声明var DirectoryHandler:{
    readDirectory(a:Path | FileQuery):FileQuery[]
    }
    类型省略=拾取
    函数orNull(fn:()=>T){
    试一试{
    返回fn();
    }捕获(e){
    返回null;
    }
    }
    声明常量路径处理程序:{
    getFromDirectory(d:Directory):FileQuery[];
    }
    
    abstract class _FileHandlerBase<T> {
      abstract readFileFromFileQuery(fq: FileQuery): Promise<T>;
      async readFile(a: Path | FileQuery, b?: Omit<FileQuery, 'path'>): Promise<T> {
        if (typeof a === 'string') a = FileQueryHandler.getFromPath(a, b);
        return this.readFileFromFileQuery(a);
      }
      async readFiles(a: (Path | FileQuery)[] | Directory, b?: Omit<FileQuery, 'path'>): Promise<T[]> {
        if (a instanceof Array) return Promise.all(a.map(p => this.readFile(p, b)));
        return this.readFiles(PathHandler.getFromDirectory(a), b);
      }
      async readFilesFromDirectory(a: Path | FileQuery, b?: Omit<FileQuery, 'path'>): Promise<T[]> {
        const ps = await DirectoryHandler.readDirectory(a);
        if (typeof a === 'string') return await (this).readFiles(ps, b);
        return await this.readFiles(ps, a);
      }
    }
    export class _FileHandler extends _FileHandlerBase<File> {
      async readFileFromFileQuery(fq: FileQuery): Promise<File> {
        const { path, encoding, flag } = FileQueryHandler.make(fq);
        const content = await promisify(fs.readFile)(path, { encoding, flag })
        return { path, encoding, flag, content };
      }
    }
    export const FileHandler = new _FileHandler();
    
    export class _FileOrNullHandler extends _FileHandlerBase<File | null> {
      async readFileFromFileQuery(fq: FileQuery): Promise<File | null> {
        return orNull(() => FileHandler.readFileFromFileQuery(fq));
      }
    }
    
    export const FileOrNullHandler = new _FileOrNullHandler();
    
    FileHandler.readFileFromFileQuery(null!) // Promise<File>
    FileOrNullHandler.readFileFromFileQuery(null!) // Promise<File | null>
    
    FileHandler.readFiles(null!) // Promise<File[]>
    FileOrNullHandler.readFiles(null!) // Promise<(File | null)[]>
    
    // Some assumptions
    type Path = string;
    
    interface FileQuery {
      path: string, flag?: string, encoding?: string | null
    }
    export interface File {
      path: string, flag?: string, encoding: string | undefined | null, content: Buffer | string
    }
    interface Directory {
      path: string, isDir: true
    }
    
    declare var FileQueryHandler: {
      make(fq: FileQuery): FileQuery
      getFromPath(s: string, b?: Omit<FileQuery, 'path'>): FileQuery;
    }
    
    declare var DirectoryHandler : {
      readDirectory(a: Path | FileQuery) : FileQuery[]
    }
    type Omit<T, K> = Pick<T, Exclude<keyof T, K>>
    
    function orNull<T>(fn: () => T) {
      try {
        return fn();
      } catch (e) {
        return null;
      }
    }
    declare const PathHandler: {
      getFromDirectory(d: Directory): FileQuery[];
    }