I am getting a problem with Typescript interfaces. I am trying to cast one object (with some fields missing such as createdBy) to another object but my casting is not working.
I hope someone can help.
Here are the interface files that I have:
interface IWord {
ascii?: number;
awl570?: boolean;
awl570Sublist?: number;
categoryId: number;
frequency?: number;
groupId: number;
lessonId: number;
name: string;
nawl963?: boolean;
nawl963D?: number;
nawl963Sfi?: number;
nawl963U?: number;
statusId: number;
syllables?: string;
toeflMcG400?: boolean;
toeic?: boolean;
wordForms: IWordForm[];
wordId: number;
createdById: number;
createdDate: string;
modifiedById: number;
modifiedDate: string;
}
interface IWordForm {
definition: string;
posId: number;
sampleSentences: [ISampleSentence];
sourceId: number;
statusId: number;
synonyms: [ISynonym];
wordFormId: number;
wordId: number;
createdById: number;
createdDate: string;
modifiedById: number;
modifiedDate: string;
}
I am trying to create this:
var wos.word = <IWord>{
categoryId: 1,
lessonId: 1,
name: null,
groupId: 1,
statusId: Status.Clean,
toefl: true,
wordForms: <IWordForm[]>[],
wordId: $stateParams.wordId
}
But getting the following error:
Severity Code Description Project File Line Suppression State Error TS2352 Neither type '{ categoryId: number; lessonId: number; name: null; groupId: number; statusId: Status; toefl: boo...' nor type 'IWord' is assignable to the other. Property 'createdById' is missing in type '{ categoryId: number; lessonId: number; name: null; groupId: number; statusId: Status; toefl: boo...'. admin C:\H\admin\admin\app\routes\words.ts 102 Active
There is a working playground example
Well, because the assignment of the expression word = <IWord>{ ...}
really does not contain createdByID, createdDate, modifedById, modifiedDate, we should simply make them nullable
interface IWord {
...
createdById?: number;
createdDate?: string;
modifiedById?: number;
modifiedDate?: string;
}
Other words - either we ask Typescript to check for us that these are NOT nullable... then we have to provide them. Or they could be missing, then the above solution is the way to go...
Test it in action here
var word = <IWord><any>{ name: null };
As Radim Köhler noted, if these fields are not required for your interface to work, it will be semantically correct to mark them as optional.
interface IWord {
categoryId: number;
groupId: number;
lessonId: number;
// ...
createdById?: number; // notice the added question marks
createdDate?: string;
modifiedById?: number;
modifiedDate?: string;
}
Or pass undefined default values (like you already do with the name
field):
var word = {
categoryId: 1,
lessonId: 1,
name: null,
// ...
createdById: undefined,
createdDate: undefined,
// ...
}
However, there are situations where you need to create an object without some of the fields. E.g. you want to create a basic object and then pass it to some other function to add missing fields.
In this case you can either split interface:
interface IWordBase {
// some of the fields that you use internally in your function
categoryId: number;
groupId: number;
lessonId: number;
frequency?: number;
// ...
}
interface IWord extends IWordBase {
// extra fields that are required in the external code, but not necessarily required when creating an object internally
createdById: number;
createdDate: string;
modifiedById: number;
modifiedDate: string;
}
Or use a hack:
// cast to <any> before casting to <IWord>
var word = <IWord><any>{
categoryId: 1,
lessonId: 1,
name: null
}
Keep in mind that by using this hack you lose all the benefits of compile-time checks. If you genuinely forget a field some day, the compilation error will be suppressed and you'll get a runtime error instead.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With