31
loading...
This website collects cookies to deliver better user experience
in
operator. in
operator is javascript feature not TypeScript.Anonymous
todo have text and id fields. Lets write an interface for itinterface AnonymousTodo {
text: string;
id: number;
}
Validated
Todo is similar to anonymous todo but with two extra fields authorName
and validationDate
. Lets write interface for it too.interface ValidatedTodo {
text: string;
id: number;
authorName: string;
validationDate: Date;
}
function printValidation(todo: AnonymousTodo | ValidatedTodo) {
}
printValidation
accepts both AnonymousTodo
and ValidatedTodo
. But if you try to console.log(log.authorName)
; you will get the following error:Property 'authorName' does not exist on type 'ValidatedTodo | AnonymousTodo'.
Property 'authorName' does not exist on type 'AnonymousTodo'.(2339)
id
instead of authorName
, that works fine. Now lets try to log text
, yes thats also works fine finally lets try to log validationDate
. we get similar error as before.ValidatedTodo
and AnonymousTodo
, in our case these common properties are id
and text
. But we want to access authorName
and validationDate
too. How can we do that? todo
can be one of the two types. It can be either of type AnonymousTodo
or ValidatedTodo
. So we need to narrow it down for TypeScript, so TypeScript will know which type it is and will allow to access the properties available on it instead of allowing us to only access common properties. If it does not make sense do not worry. I have example coming up. Hopefully it will clear things upinstanceof
,typeof
etc. But in our case as we are using interface we will narrow the type using the in
operator. The in
operator is javascript language feature which can be used to check if a property is present in an object.const myObj = {apple: 20};
if ("apple" in myObj) console.log(`We have ${myObj.apple} apples`);
apple
is present in the myObj
so we get true and a message will be logged to console. so lets integrate this in our example. Before we do that lets create objects of both type:const todoWithValidation: ValidatedTodo = { text: "Ping", id: 1, validationDate: new Date(), authorName: "admin" };
const todoWithoutValidation: AnonymousTodo = { text: "Pong", id: 1 };
ValidatedTodo
will always have validationDate
and authorName
. So we can tell TypeScript to all at these two properties to distinguish between the ValidatedTodo
and AnonymousTodo
and we can do that by adding a simple if
check which checks for these properties using the in
operator. lets write the code for this.function printValidation(todo: AnonymousTodo | ValidatedTodo) {
if ("authorName" in todo && "validationDate" in todo) {
console.log(`🔒 ${todo.authorName}, ${todo.validationDate}, ${todo.text}`);
} else {
console.log(`Anonymous ${todo.id}, ${todo.text}`);
}
}
AnonymousTodo
and inside the if
block you can only access the properties of ValidatedTodo
and outside of these scope you can only access the common properties.if ("authorName" in todo && "validationDate" in todo)
we can also use a type predicate function:function isValidatedTodo(todo: AnonymousTodo | ValidatedTodo): todo is ValidatedTodo {
return ("authorName" in todo && "validationDate" in todo);
}