Search code examples
typescripttypescript3.0

How to specify return type of function as namespace type in TypeScript so that suggestion can come up


export namespace maths {
    export function add(payload) {
        console.log(payload);
    }
    export function subtract(payload) {
        console.log(payload);
    }    
    export function multiply(payload) {
        console.log(payload);
    }      
}

export const returnNewobj = (obj, name: string) => {
    return Object.assign(obj, { name });
};

const mathsFunction = returnNewobj(maths, "mathsFunction");
mathsFunction.  // it doesn't suggest the function inside the mathsFunction

I want mathsFunction should show all the function which is available.

We can solve this using the below approach but then the problem is whenever we add a new method to maths namespace it doesn't suggest until we add it to IMaths interface

interface IMaths {
    add: (payload: number) => string;
    substract: (payload: number) => number;
}

const returnNewobj = (actions): IMaths => {
    return actions;
}

const mathsFunction = returnNewobj(maths);
mathsFunction.add(10); // here it shows the suggestion but the issue is we manuly have to sync namespace and type

Edit 1:

Also is there any way to forward this type to the react component? so that whenever we access it from props it should show list all those functions?

interface IAppProps {
   actions: any;   // how to forwarded returnNewobj type to this interface?
}

    export class App extends React.Component<AppProps,AppState> {
        constructor(props) {
            super(props);
        }

        fireAction(): void {
            this.props.actions. // should list all those functions which is in namespace
        }
        render() { return () }
    }
    
    const mapDispatchToProps = (dispatch, props) => {
        return { actions: returnNewobj(maths) };
    };
    
    export default connect(null, mapDispatchToProps)(AppComponent);

Solution

  • You need to make returnNewobj generic in order to forward the type of the target object to the result:

    export const returnNewobj = <T,>(obj:T, name: string) => {
        return Object.assign(obj, { name });
    };
    

    Playground Link

    Note: Don't use namespaces, modern modules are usually a better solution.