Skip to content

Suggestion : Documentation about a proper/clean way to reuse types/interfaces in Babel 7 #22326

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

Closed
jy95 opened this issue Mar 5, 2018 · 7 comments
Labels
Question An issue which isn't directly actionable in code

Comments

@jy95
Copy link

jy95 commented Mar 5, 2018

Hello,

I think there should be a complex example to use Babel 7 with TypeScript.
The documentation I used before this suggestion : module-class.d.ts
and babel-plugin-transform-typescript

For example, I have a library that exports a class but have inner modules to do that stuff (and I don't like Triple-Slash Directives)

For that, In the package.json, the 'types' entry refers to index.d.ts

// Type definitions for MediaScan
// Project: MediaScan
// Definitions by: jy95
/*~ This is the module template file for class modules.
 *~ You should rename it to index.d.ts and place it in a folder with the same name as the module.
 *~ For example, if you were writing a file for "super-greeter", this
 *~ file should be 'super-greeter/index.d.ts'
 */

/*~ Note that ES6 modules cannot directly export class objects.
 *~ This file should be imported using the CommonJS-style:
 *~   import x = require('someLibrary');
 *~
 *~ Refer to the documentation to understand common
 *~ workarounds for this limitation of ES6 modules.
 */

/*~ This declaration specifies that the class constructor function
 *~ is the exported object from the file
 */
export = MediaScan;

/*~ Write your module's methods and properties in this class */
declare class MediaScan extends NodeJS.EventEmitter {

    // instance properties
    protected defaultPath: string; // Default path , if paths is empty
    protected parser: MediaScanTypes.ParseFunction; // the parser to extract the useful data from name
    protected whichCategory: MediaScanTypes.WhichCategoryFunction; // Function that tell us what is the category of the TPN
    protected paths: string[]; // all the paths that will be explored
    protected categoryForFile: Map<string, MediaScanTypes.Category>; // the mapping between file and Category
    protected stores: MediaScanTypes.MapSet<MediaScanTypes.TPN | MediaScanTypes.TPN_Extended>; // where I keep the result of Category
    // static properties
    static readonly MOVIES_TYPE : MediaScanTypes.Category.MOVIES_TYPE;
    static readonly TV_SERIES_TYPE : MediaScanTypes.Category.TV_SERIES_TYPE;

    // getters
    allMovies(): Set<MediaScanTypes.TPN_Extended>;
    allTvSeries(): Map<string, Set<MediaScanTypes.TPN_Extended>>;
    allFilesWithCategory(): Map<string, string>;

    // constructor
    constructor(dataParameters?: MediaScanTypes.DataParameters, customConfig?: MediaScanTypes.CustomFunctionsConfig);

    // static methods
    static listVideosExtension(): string[];
    createFromJSON(json: MediaScanTypes.LibAsJson, customConfig?: MediaScanTypes.CustomFunctionsConfig): MediaScan;

    // instance methods
    private addNewFiles(files: string[]): Promise<any>;
    addNewPath(...paths: string[]): Promise<any>;
    hasPathsProvidedByUser(): boolean;
    scan(): Promise<any>;
    removeOldFiles(...files: string[]): Promise<any>;
    toJSON(): string;
    toJSONObject(looseMode? : boolean) : MediaScanTypes.LibAsJson;

    // filtering methods
    filterMovies(searchParameters: MediaScanTypes.SearchParameters);
    filterTvSeries(searchParameters: MediaScanTypes.SearchParameters)
}

// types , interface and another stuff used in this lib
declare namespace MediaScanTypes {
    export interface TPN {
        title: string;
        year?: number;
        resolution?: string;
        extended?: boolean;
        unrated?: boolean;
        proper?: boolean;
        repack?: boolean;
        convert?: boolean;
        hardcoded?: boolean;
        retail?: boolean;
        remastered?: boolean;
        region?: string;
        container?: string;
        source?: string;
        codec?: string;
        audio?: string;
        group?: string;
        season?: number;
        episode?: number;
        language?: string;
    }

// extended by my own purpose
    export interface TPN_Extended extends TPN {
        filePath: string;
    }

// A parsing function to be used with this lib
    export interface ParseFunction {
        (title: string): TPN | TPN_Extended;
    }

// the media files categories
    export const enum Category {
        MOVIES_TYPE = 'MOVIES',
        TV_SERIES_TYPE = 'TV_SERIES'
    }

// which category is this file
    export interface WhichCategoryFunction {
        (object: TPN): Category
    }

// The sub way to store all kind of media files found in paths
    export type MappedType<T> = Map<string, Set<T>>;
    export type MapSet<T> = Map<Category, MappedType<T> | Set<T>>;

// example '<=25'
    export type NumberSearchSyntax = string;

// to handle number operations
    export interface NumberExpressionObject {
        operator: "==" | ">" | "<" | ">=" | "<=",
        number: number
    }

    export const enum AdditionalPropertiesType {
        STRING = 'string',
        NUMBER = 'number',
        BOOLEAN = 'boolean'
    }

// additional Properties
    export interface AdditionalProperties {
        type: AdditionalPropertiesType,
        name: string,
        value: boolean | string | string[] | number | NumberSearchSyntax
    }

    export interface MinimalSearchParameters {
        additionalProperties?: AdditionalProperties[]
    }

    export interface DefaultSearchParameters extends MinimalSearchParameters {
        extended?: boolean,
        unrated?: boolean,
        proper?: boolean,
        repack?: boolean,
        convert?: boolean,
        hardcoded?: boolean,
        retail?: boolean,
        remastered?: boolean,
        season?: number | NumberSearchSyntax,
        episode?: number | NumberSearchSyntax,
        year?: number | NumberSearchSyntax,
        title?: string | string[],
        resolution?: string | string[],
        codec?: string | string[],
        audio?: string | string[],
        group?: string | string[],
        region?: string | string[],
        container?: string | string[],
        language?: string | string[],
        source?: string | string[],
    }

    // search parameters for filter functions
    export type SearchParameters = Partial<DefaultSearchParameters | MinimalSearchParameters>;

    // for filtering tuples inside SearchParameters
    export type filterTuple<T> = [string, T];

    // for optimized filtering function
    export type filterFunctionTuple = [{(set: Set<TPN>, propertiesMap: Map<string, any>)}, Map<string, any>];

    // for tuples inside json in createFromJSON
    export type mappingStringAndCategory = [string, Category];
    export type mappingStringAndTPNArray = [string, TPN[]];

    // json result to be used in createFromJSON
    export interface LibAsJson {
        allFilesWithCategory?: mappingStringAndCategory[],
        movies?: TPN[],
        series?: mappingStringAndTPNArray[],
        paths?: string[]
    }

    // the data parameters for constructor (aka first argument)
    export interface DataParameters {
        defaultPath?: string, // Default path , if paths is empty
        paths?: string[], // all the paths that will be explored
        allFilesWithCategory?: Map<string, Category>, // the mapping between file and Category
        movies?: Set<TPN | TPN_Extended>, // all the movies
        series?: Map<string, Set<TPN | TPN_Extended>>
    }

    // the custom functions (in order to have a different behaviour) for constructor (aka second argument)
    export interface CustomFunctionsConfig {
        parser?: ParseFunction,
        whichCategory?: WhichCategoryFunction
    }
}

The problem is I want to use TypeScript with Babel and import types/interfaces in files I need :

// src/MediaScan.ts
 class MediaScan extends EventEmitter {

    protected defaultPath: string; // Default path , if paths is empty
    protected parser: MediaScanTypes.ParseFunction; // the parser to extract the useful data from name
    protected whichCategory: MediaScanTypes.WhichCategoryFunction; // Function that tell us what is the category of the TPN
    protected paths: string[]; // all the paths that will be explored
    protected categoryForFile: Map<string, MediaScanTypes.Category>; // the mapping between file and Category
    protected stores: MediaScanTypes.MapSet<MediaScanTypes.TPN | MediaScanTypes.TPN_Extended>; // where I keep the result of Category
    // constants getter for external purposes (example create a custom whichCategory function)
    // workaround : const string enum aren't compiled correctly with Babel
    static readonly MOVIES_TYPE = 'MOVIES' as MediaScanTypes.Category.MOVIES_TYPE;
    static readonly TV_SERIES_TYPE = 'TV_SERIES' as MediaScanTypes.Category.TV_SERIES_TYPE;
}
@jy95 jy95 changed the title Suggestion : document a proper way to reuse types/interfaces in Babel 7 Suggestion : Documentation about a proper/clean way to reuse types/interfaces in Babel 7 Mar 5, 2018
@ghost
Copy link

ghost commented Mar 5, 2018

You can export an interface or type alias directly from a module. You don't need to use a namespace.
a.ts

export interface I { x: number; }

b.ts

import { I } from "./a";
const i: I = { x: 0 };

@jy95
Copy link
Author

jy95 commented Mar 5, 2018

Thanks for the support. The thing I suggest in OP was to use the .d.ts file for the types entry point in package.json.
For example :
index.d.ts

// import custom interfaces/types
import { I } from "./src/b";
declare class X implements I {
    // ...
}

/src/b.ts

export interface I { x: number; }

Edit : I heard that could be some name conflict when using modules that uses same name for interface/types. Didn't know if the module class template prevent this case when stripped of the namespace for Babel ...

@ghost
Copy link

ghost commented Mar 5, 2018

The compiler can automatically generate .d.ts files for you using --declaration. You don't need to write a .d.ts file manually. So I would just write index.ts normally, and generate index.js and index.d.ts with the compiler.

@jy95
Copy link
Author

jy95 commented Mar 5, 2018

The suggested config used here set noEmit :

tsc --init --noEmit --allowJs --allowSyntheticDefaultImports --target esnext

And as the docs said :

Do not emit outputs.

I think a --declarationOnly flag can be useful to handle case like that ..

Edit:

My main file has this d.ts after tsc

export {};

@ghost
Copy link

ghost commented Mar 5, 2018

For that you can use the --emitDeclarationOnly flag (#20735) (microsoft/TypeScript-Handbook#730)

@jy95
Copy link
Author

jy95 commented Mar 5, 2018

Thanks. No wonder I didn't know that stuff : that is something new not yet in the docs online. Another stuff that could be added inside the TypeScript-Babel-Starter repo ^^

@mhegazy mhegazy added the Question An issue which isn't directly actionable in code label Mar 5, 2018
@typescript-bot
Copy link
Collaborator

Automatically closing this issue for housekeeping purposes. The issue labels indicate that it is unactionable at the moment or has already been addressed.

@microsoft microsoft locked and limited conversation to collaborators Jul 25, 2018
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
Question An issue which isn't directly actionable in code
Projects
None yet
Development

No branches or pull requests

3 participants