简体   繁体   中英

TypeScript class interface definition

I'm trying to create a definition file ( *.d.ts ) for a third party library. This library has a base class that the user objects will end up being inherited from. However, the library handles the construction of those objects and merges their own built-in methods with the user defined methods. So, I can't just create an interface which the user class implements since the user class doesn't define the built-in methods from the base class.

TypeScript definitions d.ts file:

module otherlib {
    export interface Base {
        third_party_base_method(): string;
    }
}

User source:

// FAILS because MyClass doesn't define third_party_base_method()
class MyClass implements otherlib.Base {
    myfunc() {
        let str = this.third_party_base_method();
    }
}    

A workaround I currently have is to create a TypeScript file ( *.ts ) which defines a class instead of an interface with all of the methods in the base type with empty bodies or return dummy values. The user classes can then extend from this so the type checking works. But, this seems really hacky and causes unnecessary and potentially dangerous prototype manipulation. Is there a better way?

TypeScript .ts file to define third-party library base class:

module otherlib {
    export class Base {
        // Dummy stub definition that is never called
        third_party_base_method(): string { return "dummy"; }
    }
}

User source:

class MyClass extends otherlib.Base {
    myfunc() {
        // Proper type checking for calling the method that the
        // third party library adds to the object.
        let str = this.third_party_base_method();
    }
}

UPDATE :

I did in fact start to run into some trouble with extending with the empty stub functions. So, my new workaround is just to create a stub to make casting easier...

TypeScript d.ts file to define third-party library base class:

module otherlib {
    export interface Base {
        third_party_base_method(): string;
    }
}

TypeScript .ts file for casting stub:

module otherlib_stub {
    export class Base {
        get base(): otherlib.Base { return <otherlib.Base><any>this; }
    }
}

User source:

class MyClass extends otherlib_stub.Base implements otherlib.Base {
    myfunc() {
        // Proper type checking for calling the method that the
        // third party library adds to the object.
        let str = this.base.third_party_base_method();
    }
}  

You should use an ambient declaration. This provides the type information, but doesn't generate any code in the JavaScript output:

declare module otherlib {
    export class Base {
        third_party_base_method(): string;
    }
}

You can put this in a file with the .d.ts extension, to make it clear that it isn't an implementation file.

Update!

It depends on exactly how the third party library works, but you could use an interface to wrap the external members and your local members into a single type.

The example below assumes you call a method that returns your extended class. You'll have to supply an example of how it actually works if you need help crafting the exact version of this.

declare module otherlib {
    export interface Base {
        third_party_base_method(): string;
    }

    export function externalCodeThatExtendsYourClass<T>(obj: any): T;
}

// You would need the class/interface pair for each class
class Example {
    yourMethod() {
        alert('All yours');
    }
}

// The interface wraps the class members and the externally added members into a single type
interface ExtendedExample extends Example, otherlib.Base { }


var example = otherlib.externalCodeThatExtendsYourClass<ExtendedExample>(new Example());

example.third_party_base_method();
example.yourMethod();

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM