difference among typeof, instanceof, keyof and in
In TypeScript, the
typeof,instanceof,keyof, andinoperators each serve distinct roles in type manipulation and object inspection. This post will delve into each of these operators, providing clear examples and use cases.
typeof Operator
The typeof operator is used to determine the type of a variable or value at runtime. It returns a string indicating the type.
let myNumber = 123;
console.log(typeof myNumber); // Output: number
let myString = "hello";
console.log(typeof myString); // Output: string
In the example above, typeof myNumber returns "number" because myNumber is a number. Similarly, typeof myString returns "string" because myString is a string.
Returnable Types
The following types can be returned by the typeof operator:
"undefined": Forundefinedvalues."boolean": For boolean values."number": For numeric values (Number)."bigint": For numbers larger than the Number type."string": For string values."symbol": For Symbol values (introduced in ECMAScript 2015)."function": For functions."object": For all other objects, including arrays and null.
Note that number is a 64-bit floating point format. See Double-precision floating-point format for more details.
bigintis for Arbitrary-precision arithmetic.
instanceof Operator
The instanceof operator checks if an object is an instance of a particular class or constructor function.
In JavaScript, it verifies the existence of a function’s prototype. In TypeScript, it confirms whether a variable conforms to the datatype of a class. It returns a boolean value.
function Car(make, model, year) {
this.make = make;
this.model = model;
this.year = year;
}
const auto = new Car('Honda', 'Accord', 1998);
console.log(auto instanceof Car); // true
Car.prototype = {};
console.log(auto instanceof Car); // false
In the first console.log, auto is an instance of Car, so it returns true. However, after changing Car.prototype, the second console.log returns false because auto is no longer considered an instance of the modified Car constructor.
class User {
name: string;
constructor(name: string) {
this.name = name;
}
}
const person = new User('username');
console.log(person instanceof User); // true
person is an instance of the User class, so the expression returns true.
Type Guard
When multiple classes implement the same interface, instanceof helps to determine the specific class of an object, implementing a type guard.
class Foo {}
class Bar extends Foo {}
class Bas {}
var bar = new Bar();
console.log(bar instanceof Bar); // true
console.log(bar instanceof Foo); // true
console.log(bar instanceof Object); // true
console.log(bar instanceof Bas); // false
Here, bar is declared as type Bar, inheriting from Foo. The console.log statements return true when checking against Foo or Bar. A type guard goes further, ensuring that actions are performed based on the specific type (Foo or Bar) of bar. Especially with generic types, this prevents type errors by ensuring clarity before function execution.
keyof Operator
The keyof operator is used to create a union of keys from an object type.
JSON
let myObject = { name: "John", age: 30 };
let myObjectKey: keyof typeof myObject; // 'name' | 'age'
myObjectKey = 'name';
In this example, myObjectKey can be either "name" or "age" because keyof typeof myObject creates a union of the keys of myObject. Using keyof enhances type safety by restricting the possible values of myObjectKey to the existing keys of myObject. Note the necessity of combining with typeof to achieve the desired result. Type variables offer a simpler approach.
Type
The keyof operator can also be used with Type variables.
type User = { name: string, age: number, address: string };
let userKey: keyof User;
// 'name' | 'age' | 'address'
In this example, userKey can be "name", "age", or "address" because keyof User creates a union of the keys defined in the User type.
in Operator
The in operator checks if an object or array has a specific property. Commonly used to verify the existence of keys in JSON objects or values in enums.
let myObject = { name: "John", age: 30 };
console.log("name" in myObject); // Output: true
console.log("email" in myObject); // Output: false
The in operator returns true because myObject has a "name" property and false because it does not have an "email" property.
Index in Array
In arrays, in checks for index existence, not value existence.
let count = ['one', 'two', 'three', 'four'];
0 in count // true
(1 + 2) in count // true
6 in count // false
"one" in count // false, should be index value, not content.
"length" in count // true, because length is a property of the array.
Key in JSON
In JSON, in verifies key existence.
let user = {
name: 'username',
age: 10
}
console.log('name' in user) // true
Dynamic Key in Type
You can define restricted, variable keys in JSON, utilizing only the key values from defined JSON or types.
let myObject = { name: "John", age: 30 };
type ObjType = {
[key in keyof typeof myObject]: number // 'name' | 'age'
}
Types can simplify this further:
type AllowedKeys = 'name' | 'age';
type ObjType1 = {
[key in AllowedKeys]: number // 'name' | 'age'
}
Not Working in Interface
Using in with an interface results in an error because interfaces only define the shape of an object, not its actual contents.
interface User {
name: string;
age: number;
}
let anotherUser: User = {
name: 'anotheruser',
age: 20
}
console.log('name' in User) // error
console.log('name' in anotherUser) // true
In summary, typeof, instanceof, keyof, and in operators serve specific purposes in TypeScript for type and property checking. Proper usage enhances code reliability and enables efficient type manipulation.
댓글남기기