Skip to content

Guide on implementing typings for the packages. #12

@ejnshtein

Description

@ejnshtein

After some research, here is the third version of implementing extendable typings for packages.

1. Modules

TS docs: https://www.typescriptlang.org/docs/handbook/modules.html

Modules are considered a modern way of structuring code.

Example folder structure:

├── 📁 some-package-name
|  ├── 📁 api
|  |  ├── 📄 Api.processor.js
|  |  ├── 📄 Api.query.js
|  |  ├── 📄 Api.request.js
|  |  └── 📄 Api.type.js
|  ├── 📁 component
|  |  ├── 📁 First
|  |  |  ├── 📄 index.js
|  |  |  ├── 📄 First.component.js
|  |  |  └── 📄 First.container.js
|  |  └── 📁 Second
|  |  |  ├── 📄 index.js
|  |  |  ├── 📄 Second.component.js
|  |  |  └── 📄 Second.container.js
|  ├── 📁 context
|  |  ├── 📄 File.context.js
|  |  └── 📄 File.provider.js
|  ├── 📁 plugin
|  └── 📄 package.json

To add typings for any of the following files we can use the following method:

// lets write typings for the file ./component/First/First.component.js

// import necessary dependencies
import React from 'react';
import { FileType } from '../../context/File.context';

// declare that we are located in this module
declare module 'some-package-name/src/component/First/First.component' {
    // write typings
    interface FirstComponentProps {
        file: FileType
    }

    interface FirstComponentState {}

    class FirstComponent extends React.PureComponent<FirstComponentProps, FirstComponentState> {
        getContextValue(): FileType
    }
}

// if necessary, export default outside module declaration
export default FirstComponent;
  1. We imported type dependency for React as in any other dependency in js file.
  2. We declared types for FirstComponent inside a module.
  3. We don't need to write export inside module declaration, they are exported by default.
  4. We exported FirstComponent as default export outside of the declared module.
    TS does not allow to export default types inside module declaration, because it can possibly interfere with other packages.
  5. FirstComponentState interface is empty, rather it doesn't have an initial state. Even tho it's empty, we still need to declare that it exists and we can extend it later by other modules or plugins.

That is it! We made a module! Now we can start playing with our modular code, extend it and bring life to the modular types!

2. Overrides & Extends

Now, we have a package with its module and typed component module ./component/First/First.component.
If we go to some-package-name-extended package which has a plugin that adds to the component First.component additional state, we can define it in typings as well.

Now we need to actually extend types.

declare module 'some-package-name/src/component/First/First.component' {
    // and same type name
    interface FirstComponentState {
        extendedState?: Record<string, string>
    }
}

That is it, we have just extended our component state!

Now if we import the original component, that is extended by our plugin, and go to its state we will see that it is extended.

3. Notes

3.1 Empty interfaces

To be able to easily override components types we need to define all types for React.Component generics, even if they are empty.

declare module 'some-package-name/src/component/First/First.component' {
    interface FirstComponentProps {
        product: ProductType
    }

    interface FirstComponentState {}

    class FirstComponent extends React.PureComponent<ProductProviderProps, ProductProviderState> {
        getSomeDataMethod(): SomeDataTypeReturnedByMethod

        render(): JSX.Element
    }
}

// other module
declare module 'some-package-name/src/component/First/First.component' {
    interface FirstComponentState {
        myAddedState?: Record<string, string>
    }
}

3.2 Useful links

https://stackoverflow.com/questions/39853825/how-to-extend-an-interface-declared-in-an-external-library-d-ts/44828876
https://stackoverflow.com/questions/30357634/how-do-i-use-namespaces-with-typescript-external-modules
https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/master/types/material-ui/index.d.ts
https://www.typescriptlang.org/docs/handbook/namespaces.html
https://www.typescriptlang.org/docs/handbook/triple-slash-directives.html

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions