gristlabs/ts-interface-checker

TypeError: checkerFunc is not a function error with nested interfaces

eurydice76 opened this issue · 3 comments

Hi,

I have the following interfaces written in separate files:

// account-dto.ts
import { RoleDTO, SiteDTO } from "./";

export interface AccountDTO {
    id : number;
    firstName : string;
    lastName : string;
    login : string;
    sites ?: SiteDTO[];
    roles ?: RoleDTO[];
}

// role-dto.ts
import { AccountDTO } from './'

export interface RoleDTO {
    id : number;
    name : string;
    accounts ?: AccountDTO[];
}

// server-dto.ts
import { SiteDTO } from './'

export interface ServerDTO {
    id : number;
    name : string;
    description ?: string;
    basePath : string;
    confPath : string;
    enabled : boolean;
    sites ?: SiteDTO[];    
}

// site-dto.ts
import { AccountDTO, ServerDTO } from "./";

export interface SiteDTO {
    id : number;
    path : string;
    cgi : boolean;
    server : ServerDTO;
    accounts : AccountDTO[];
}

From there, I create my checker like so:

import accountTI from "../dtos/account-dto-ti";
import roleTI from "../dtos/role-dto-ti";
import serverTI from "../dtos/server-dto-ti";
import siteTI from "../dtos/site-dto-ti";

const checkers = createCheckers(siteTI,serverTI,accountTI,roleTI);
for (const site of sites) {
    try {
        checkers.SiteDTO.strictCheck(site);
    } catch (err) {
        res.status(400).send(`Invalid type for site: ${err.message}`);
        return;
    }
}

Doing so, I get the following error:


(node:120641) UnhandledPromiseRejectionWarning: TypeError: checkerFunc is not a function
    at Array._checkerBeingBuilt (/home/pellegrini/git/apachegen-be/node_modules/ts-interface-checker/dist/types.js:66:70)
    at /home/pellegrini/git/apachegen-be/node_modules/ts-interface-checker/dist/types.js:421:51
    at Array.map (<anonymous>)
    at TIface.getChecker (/home/pellegrini/git/apachegen-be/node_modules/ts-interface-checker/dist/types.js:420:41)
    at TName._getChecker (/home/pellegrini/git/apachegen-be/node_modules/ts-interface-checker/dist/types.js:79:29)
    at TName.getChecker (/home/pellegrini/git/apachegen-be/node_modules/ts-interface-checker/dist/types.js:68:36)
    at TArray.getChecker (/home/pellegrini/git/apachegen-be/node_modules/ts-interface-checker/dist/types.js:127:38)
    at /home/pellegrini/git/apachegen-be/node_modules/ts-interface-checker/dist/types.js:416:79
    at Array.map (<anonymous>)
    at TIface.getChecker (/home/pellegrini/git/apachegen-be/node_modules/ts-interface-checker/dist/types.js:416:39)
(Use `node --trace-warnings ...` to show where the warning was created)
(node:120641) UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). To terminate the node process on unhandled promise rejection, use the CLI flag `--unhandled-rejections=strict` (see https://nodejs.org/api/cli.html#cli_unhandled_rejections_mode). (rejection id: 1)
(node:120641) [DEP0018] DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a non-zero exit code.

Would you know what I do wrong with my interface declarations ?

Many thanks

Close to the error is a comment:

    // Note also that this is about handling recursive types; it does NOT help validating data
    // with circular references.

I can't see any other mention of the word 'circular' so I think the library just doesn't support circular type definitions. In this case AccountDTO contains SiteDTO which contains AccountDTO.

That doesn't mean it's impossible to add support for circular definitions, but it may not happen without an external PR.

ok thanks for the quick answer

Actually, I think that comment is a red herring here (it's about circular data, while the actual problem here is circular definitions). Circular definitions should be handled, and the fact that it's not here seems an actual bug in ts-interface-checker.

I think the culprit is this bit of code in TIface:

    // Consider a prop required if it's not optional AND does not allow for undefined as a value.
    const isPropRequired: boolean[] = this.props.map((prop, i) =>
      !prop.isOpt && !propCheckers[i](undefined, testCtx));

It actually calls the checker in the process of building another checker. But for handling circular type definitions, we assume that checkers won't actually be called until all of them are finished getting built.