Home > database >  How do you declare the type a property of an object in-place, without needing to declare the type of
How do you declare the type a property of an object in-place, without needing to declare the type of

Time:01-01

Is there a way to type a property of an object as you’re writing the object? As opposed to defining a type/interface beforehand.

The only thing I can think of is as but that’s too lenient. Consider:

type Comment = Required<{
    author: string;
    message: string;
}>;

const myComment: Comment = {
    author: 'Steve',
    // Error! :) 'message' is missing
};

const myData = {
    myComment: {
        author: 'Steve',
        // No error. :(
    } as Comment,
};

const myData = {
    myComment: <Comment>{
        author: 'Steve',
        // No error. :(
    },
};

I want myData.myComment to throw the same error.

This is a trivial example, of course. But if I'm writing a big complex object it would be nice to be able to declare types for portions of it on-the-fly.

CodePudding user response:

Would an anonymous/inline interface work? You still need it to precede the object but it's more concise than interface/type:

const myData: { myComment: Comment } = {
  myComment: {
    author: 'Steve',
    // error
  },
};

CodePudding user response:

One option is to use IIFEs, although it's ugly and has (extremely) minor performance implications:

const myData = {
    myComment: ((): Comment => ({
        author: 'Steve',
        // Error! 'message' is missing
    }))(),
};

CodePudding user response:

Perhaps this is what you're asking: https://stackoverflow.com/a/12787919/4771663

You can declare the object literal type during the assignment:

const myData: { myComment: Comment } = {
    myComment: {
        author: 'Steve',
    }
}

CodePudding user response:

Note: Comment is a built-in type in lib.dom.d.ts. If you use that identifier with the dom library, you'll get this error:

Duplicate identifier 'Comment'.(2300)

You can use an identity function to ensure that the input is assignable to the parameter type:

TS Playground

type C = {
  author: string;
  message: string;
};

/** If you use this, you MUST provide the generic type argument to constrian your value */
function id <T>(value: T): T {
  return value;
}

const number1 = id<number>('hello'); /*
                           ^^^^^^^
Argument of type 'string' is not assignable to parameter of type 'number'.(2345)
*/

// Don't forget to supply the generic type argument!
const number2 = id('hello'); // typeof value2 === "hello"

const myData1 = {
  myComment: id<C>({
    author: 'Steve',
    // message: 'Hi',
  }), /*
^^^^^^^^^^^^^^^^^^^^^^^^^
Argument of type '{ author: string; }' is not assignable to parameter of type 'C'.
  Property 'message' is missing in type '{ author: string; }' but required in type 'C'.(2345) */
};

const myData2 = {
  myComment: id<C>({
    author: 'Alex',
    message: 'Hello',
  }), // ok
};

console.log(myData1); // { myComment: { author: 'Steve' } }
console.log(myData2); // { myComment: { author: 'Alex', message: 'Hello' } }

Alternatively, if you're simply trying to avoid typing, you can define the comment ahead of the object in which you want to include it, like this:

TS Playground

type C = {
  author: string;
  message: string;
};

let myComment: C = {
  author: 'Steve',
  message: 'Hi',
};

const myData1 = { myComment };

myComment = {
  author: 'Alex',
  message: 'Hello',
};

const myData2 = { myComment };

console.log(myData1); // { myComment: { author: 'Steve', message: 'Hi' } }
console.log(myData2); // { myComment: { author: 'Alex', message: 'Hello' } }
console.log(myComment); // { author: 'Alex', message: 'Hello' }
  • Related