Title: Strongly typed casting in Typescript
Tags: typescript
Question: Is there any way to get an error if an object type casted to an interface doesn't have the prototype/structure defined by the Interface?
interface IUser {
id : string,
name : string,
address : string
Filling only few properties of IUser
let data : any = {}; //let data : IUser = <IUser&gt;{};
data.id = "123";
data.name = "name";
Expecting a compile time error below.
const user : IUser = <IUser&gt;data; //<= Any way to get an error here saying address property doesn't exist at compile time?
Update : Adding the context why such a requirement exists.
Consider IUser interface has many properties and don't want to miss assigning any property while constructing it. And only a compilation error will be of more help in this case. This is mainly for passing DTO objects in DDD design. And these are usually with numerous parameters.
Comment: How can I make sure user object has all properties assigned? (assuming we set properties in each separate statement rather than assigning at initialisation)?

Comment: @kaya3 I see your point. But unfortunately, the IUser has many properties (around 10) and all adding to constructor may not be possible. Also, the code is mainly for assigning data for DTO (DDD design) objects. While filling the dto, I just want to make sure I don't miss any properties - just to avoid missing field issues.

Comment: @ritaj Removing any won't make it work either. If I replace it with  i need to initialise the object at the time of assignment which is not possible for me as the properties assignment has more code than a direct assignment. So want to have it in separate lines for each assignment.

Comment: @A.Chiesa Can you please explain "store each property in a support variable"?

Comment: @ritaj Can you please provide an example? Looks like thats not working either.

Comment: @Ayyappa then store each property in a support variable. The ONLY way the compiler is going to help you is checking that some object literal satisfies the interface as a whole.

Comment: Edited my answer. It's really, really simple: just help the compiler telling him what to expect.

Comment: `data` is of type `any`, which is assignable to everything (except `never`) and therefore (intentionally) an unsound type. If you want type safety, do not use `any`. Moreover, type assertions like `data` are also an intentionally unsound language feature.

Comment: The usual way to do this is to write a `class User implements IUser` and then the constructor will check that you assign all three of `this.id`, `this.name` and `this.address`.

Comment: Just remove `: any` and ``

Comment: No, don't replace it with anything. Just remove `any`. Or do `let data : Partial = {};`


Here is another answer: interface has many properties and don't want to miss assigning any property while constructing it
You can use a builder to incrementally add properties to an object in a typed way:
function build<T extends object, K extends string, V&gt;(
o: T, name: K, val: V): asserts o is T &amp; { [P in K]: V } {
(o as any)[name] = val // add property
// safe cast, we just fulfill function's type contract
let data = {};
build(data, &quot;id&quot;, &quot;123&quot;)
data // { id: string; }
build(data, &quot;name&quot;, &quot;Lui&quot;)
data // { id: string; } &amp; { name: string; }
let user: IUser = data // error: address is missing
build(data, &quot;address&quot;, &quot;Buenos Aires&quot;)
user = data // data is now assignable to IUser
build behaves similar to a variable assignment and mutates the passed in data. It makes use of an assertion function to add every new property via control flow to the type of data.
Playground
Explanation
build receives three arguments: an object o, name and val, so it can add a property to o. Now, the interesting part is the return type asserts o is T &amp; { [P in K]: V }.
Let's first explain T &amp; { [P in K]: V }: It means, you get back the type of whatever object o with type T you passed in plus the newly added property with name K and value V (&amp; { [P in K]: V }).
asserts o is similar to a type guard, but instead of the latter using two conditional branches (if/else) it just asserts a value to be of certain type. Usually you throw in an assertion function, when conditions are not met. Here we just make use of its capability to narrow the function arg o: T in the surrounding scope via control flow. Note: assertion functions cannot return anything.
Effectively, you get a nice incremental builder.
Comment for this answer: @Ayyappa added an explanation to the answer.
Comment for this answer: It is a [mapped type](https://www.typescriptlang.org/docs/handbook/advanced-types.html#mapped-types).
Comment for this answer: This looks pretty neat. Can you please explain in detail about build function more?
Comment for this answer: I think i'm close enough. Can you please explain this syntax "[P in K]: V". I think with that I get complete clarity. I understood that by the time we assign to user, compiler knows that the object contains list of keys added till that point and helping while assigning to detect any missing attributes.

Here is another answer: Well, it depends.
For starters: the TypeScript compiler, being a compiler, is not capable of checking david23@example.org. It can check the typings you have in your code.
So, if you have just some random data that comes from an external source, the TypeScript compiler cannot do nothing for you at runtime: your problematic data is built long after the compiler has performed is task. To do this, you need some runtime check system, like io-ts.
If your needs are more limited, you could just write a custom type guard. Something like (untested code ahead):
function isIUser(obj: any): obj is IUser {
return obj &amp;&amp; typeof obj.id === 'string' &amp;&amp; typeof obj.name === 'string' &amp;&amp; typeof obj.address === 'string';
let data : any = {}; //let data : IUser = <IUser&gt;{};
data.id = "123";
data.name = "name";
if (isIUser(data)) {
// inside this block data is of type IUser
} else {
// error
Second: a TypeScript cast doesn't really perform any operation or check. It is a way to tell the TS Compiler "trust me, I know better than you, this is really an IUser".
And, being an obedient piece of software, the compiler trusts you whatever you pass: good data, bad data, strings, numbers, undefined, you name it. So, limit your casts to a minimum.
The compiler is going to thoroughly perform checks for you if you allow him to perform its work:
// Do NOT use any as a type. Tell the compiler what he should enforce
const data : IUser = {
id: "123",
name: "name"
}; // --&gt; compile time error.
if you need to call procedures or other, you just use support variables:
// telling the compiler the result must honor the IUser interface
mapIUserDto(userInputs: Something): IUser {
const name = this.normalizeName(userInputs.name),
address = this.mapAddress(userInputs);
// using object composition you colud skip even property names
// if a property is missing, you'll get a nice error message.
return {
id: userInputs.id,
name: name,
address: address
Comment for this answer: Edit gave a great idea! I see it should work! If you have any other better versions please do share. Else, will stick to this. I'm looking for compile time error only but not runtime.
Comment for this answer: If it works, you could mark the question as answered.

{'source': 'StackExchangeDataset', 'subset': 'stackoverflow.com', 'metadata': {'AnswerCount': 2, 'CommentCount': 11, 'ContentLicense': 'CC BY-SA 4.0', 'CreationDate': '2020:00:03/02/20', 'FavoriteCount': None, 'PostTypeId': 1, 'Tags': '<typescript>', 'Title': 'Strongly typed casting in Typescript', 'ViewCount': 406, 'id': 60493090, 'user_AboutMe': '<p>Video Game Developer, India</p>\n', 'user_AccountId': 180160.0, 'user_DisplayName': 'Ayyappa', 'user_Reputation': 1738.0, 'user_Views': 468.0, 'user_id': 413306.0}}