Infer the interface of an object in TypeScript

Viewed 261

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?

1 Answers

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
    });
};
Related