Search code examples
typescriptmoduleinterfaceinitialization

Infer the interface of an object in TypeScript


Suppose I have a TypeScript interface in a module, and also a function that return an initialized object of that interface:

export default interface Foo {
    name: string;
    surname: string;
    cars: number;
};

export function newFoo(): foo {
    return <Foo>{
        name: '',
        surname: '',
        cars: 0
    };
};

The problem is that I'm typing all the fields twice, and it's not only boring, but also error-prone.

I can't really use return <Foo>{}; because there are cases of objects being members of other objects, so I'll have missing properties and undefined pops out.

I could check if the property exists when calling it, but since the property doesn't have the ?, it means it's mandatory, so it's supposed to be there.

So, is there a better way to write the code above?


Solution

  • You can reverse the way you type your Foo and function, and have Foo be whatever is the return type of newFoo:

    export type  Foo = ReturnType<typeof newFoo>
    
    export function newFoo() {
        return {
            name: '',
            surname: '',
            cars: 0
        };
    };
    

    If you want some members to be optional or not initialized by newFoo you will have to do a bit of work to add those in, although this might be overkill for complex scenarios:

    export type  Foo = ReturnType<typeof newFoo>
    
    export function newFoo() {
        const optionalInitiazlised = {
            optionaButInited: ""
        }
    
        return  Object.assign(optionalInitiazlised as Partial<typeof optionalInitiazlised>,
            {} as { optionalProp?: string }, {
            name: '',
            surname: '',
            cars: 0
        });
    };