Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Possible typed version of wrapper function #1

Open
MJochim opened this issue Oct 11, 2019 · 0 comments
Open

Possible typed version of wrapper function #1

MJochim opened this issue Oct 11, 2019 · 0 comments

Comments

@MJochim
Copy link

MJochim commented Oct 11, 2019

I found that there is indeed a super easy way of creating a typed wrapper. I think we should consider this.

This is the wrapper function we want to write for NPM anyway, only slightly modified to integrate methodName and methodOptions into one parameter:

function wrapPerformAssp(
        inputFilename: string,
        outputFilename: string,
        methodNameAndOptions: AsspMethodNameAndOptions,
        outputFormat: "TSV" | "SSFF")
{
    const api = {
        performAssp: Module.cwrap(
            'performAssp',
            'number',
            ['string', 'string', 'string', 'string', 'string']
        );
    };

    api.performAssp(
        inputFilename,
        outputFilename,
        methodNameAndOptions.name,
        JSON.stringify(methodNameAndOptions.options),
        outputFormat
    );
}

Then we only need a type definition for each of the ASSP methods (forest, rmsana, ...), but no method-specific function body is required. Everything is handled by the above wrapPerformAssp. The type definitions look like this:

interface ForestOptionsObject {
    beginTime?: number;
    endTime?: number;
    effectiveLength?: boolean;
    windowSize?: number;
    gender?: "m" | "f";
};

interface RmsAnaOptionsObject {
    beginTime?: number;
    centerTime?: number;
    endTime?: number;
    linear?: boolean;
};

type AsspMethodNameAndOptions = {
    name: "forest";
    options: ForestOptionsObject;
} | {
    name: "rmsAna";
    options: RmsAnaOptionsObject;
};

Now the caller is type safe:

let foo: AsspMethodNameAndOptions = {
    name: "forest",
    options: {
            beginTime: 2,
            endTime: 1,
            linear: true
    }
};

wrapPerformAssp("input", "output", foo, "TSV");

This does not compile because I used an rmsana option (linear) but called forest. The compiler error looks like this, which imo is extremely helpful:

> tsc main.ts

main.ts:64:13 - error TS2326: Types of property 'options' are incompatible.
  Type '{ beginTime: number; endTime: number; linear: boolean; }' is not assignable to type 'ForestOptionsObject'.
    Object literal may only specify known properties, and 'linear' does not exist in type 'ForestOptionsObject'.

64             linear: true
               ~~~~~~~~~~~~


Found 1 error.

Problem

The only problem I see is that the required type definitions duplicate the method-specific option lists from https://github.com/IPS-LMU/wasmassp/blob/master/performAssp.c. That’s 10 methods with a total of about 130 options – which translates to about 200 lines of Typescript definitions.

But I really think this is worth the trouble.

To avoid any problems with future changes to method or option names (remember though that they haven’t changed in at least six years and most likely even longer), we could include a unit-test-like shell script that compares performAssp.c and the Typescript definitions file in this respect and rings an alarm if there is a mismatch.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant