Table of Contents#
- Question 1: Basic Object Definition
- Question 2: Optional Properties in Interfaces
- Question 3: Function Types in Interfaces
- Question 4: Readonly Properties in Objects
- Question 5: Extending Interfaces
- Question 6: Index Signatures in Interfaces
- Common Practices and Best Practices
- Conclusion
- References
Question 1: Basic Object Definition#
Question#
Which of the following is the correct way to define a TypeScript object with a name property of type string and an age property of type number?
// Option A
const person = {
name: 'John',
age: 25
};
// Option B
const person: {name: string, age: number} = {
name: 'John',
age: 25
};
// Option C
let person = {
name: 'John',
age: 25
} as {name: string, age: number};Answer#
The correct answer is Option B.
In TypeScript, you can explicitly type an object when you define it. Option A doesn't explicitly define the types of the object properties. TypeScript will infer the types (string for name and number for age), but it's better to be explicit for better readability and maintainability. Option C uses the type assertion (as keyword), which is generally used when you want to override TypeScript's type inference. Option B is the cleanest way to define an object with explicit types.
// Example of Option B
const person: {name: string, age: number} = {
name: 'John',
age: 25
};
console.log(person.name); // Output: John
console.log(person.age); // Output: 25Question 2: Optional Properties in Interfaces#
Question#
How can you define an optional property in an interface?
// Option A
interface User {
name: string;
age?: number;
}
// Option B
interface User {
name: string;
age: number | undefined;
}
// Option C
interface User {
name: string;
age: number;
age?: number;
}Answer#
The correct answer is Option A.
In TypeScript, you can mark a property as optional in an interface by appending a ? after the property name. Option A correctly defines an age property as optional. Option B defines the age property as a union type of number or undefined, which is different from an optional property. An optional property may or may not exist in an object that implements the interface, while a property of type number | undefined must exist but can have the value undefined. Option C is incorrect because you can't have the same property name defined both as required and optional.
// Example of Option A
interface User {
name: string;
age?: number;
}
const user1: User = { name: 'Alice' };
const user2: User = { name: 'Bob', age: 30 };
console.log(user1.name); // Output: Alice
console.log(user2.age); // Output: 30Question 3: Function Types in Interfaces#
Question#
How can you define an interface with a function property?
// Option A
interface Calculator {
add: (a: number, b: number): number;
}
// Option B
interface Calculator {
add(a: number, b: number): number;
}
// Option C
interface Calculator {
add: function(a: number, b: number): number;
}Answer#
Only Option B is correct.
Option A uses incorrect syntax add: (a: number, b: number): number;. In TypeScript, the correct way to define a function type using arrow function syntax is add: (a: number, b: number) => number; (using => instead of : before the return type). Option B is a shorthand syntax for defining a function property in an interface. Option C is incorrect because the function keyword is not used in this way to define a function type in an interface.
// Example of corrected Option A (with proper syntax)
interface Calculator {
add: (a: number, b: number) => number;
}
const calc: Calculator = {
add: (a, b) => a + b
};
console.log(calc.add(2, 3)); // Output: 5Question 4: Readonly Properties in Objects#
Question#
How can you define a readonly property in an object?
// Option A
const person = {
readonly name: 'John',
age: 25
};
// Option B
interface Person {
readonly name: string;
age: number;
}
const person: Person = {
name: 'John',
age: 25
};
// Option C
let person = {
name: 'John',
age: 25
};
Object.freeze(person.name);Answer#
The correct answer is Option B.
In TypeScript, you can define a readonly property in an interface using the readonly keyword. Once an object implements the interface, the readonly property cannot be reassigned. Option A is incorrect because the readonly keyword is not used in this context directly on an object literal. Option C is incorrect because Object.freeze freezes the entire object, not just a single property, and the syntax is also incorrect as Object.freeze expects an object, not a property value.
// Example of Option B
interface Person {
readonly name: string;
age: number;
}
const person: Person = {
name: 'John',
age: 25
};
// person.name = 'Jane'; // This will cause a compilation error
person.age = 26;
console.log(person.age); // Output: 26Question 5: Extending Interfaces#
Question#
How can you extend an interface in TypeScript?
// Option A
interface Shape {
color: string;
}
interface Square extends Shape {
sideLength: number;
}
// Option B
interface Shape {
color: string;
}
interface Square = Shape + {
sideLength: number;
};
// Option C
interface Shape {
color: string;
}
interface Square {
extends Shape;
sideLength: number;
}Answer#
The correct answer is Option A.
In TypeScript, you can use the extends keyword to create a new interface that inherits the properties of an existing interface. Option A correctly extends the Shape interface to create the Square interface. Option B uses an incorrect syntax; there is no + operator for interface extension. Option C has an incorrect placement of the extends keyword within the interface definition.
// Example of Option A
interface Shape {
color: string;
}
interface Square extends Shape {
sideLength: number;
}
const mySquare: Square = {
color: 'red',
sideLength: 5
};
console.log(mySquare.color); // Output: red
console.log(mySquare.sideLength); // Output: 5Question 6: Index Signatures in Interfaces#
Question#
What is the purpose of an index signature in an interface?
interface StringArray {
[index: number]: string;
}Answer#
An index signature in an interface is used to describe the type of an object that can be accessed by an index. In the example above, the StringArray interface has an index signature [index: number]: string;. This means that the object implementing this interface can be accessed using a numeric index, and the value at that index will be a string.
// Example usage
interface StringArray {
[index: number]: string;
}
const myArray: StringArray = ['apple', 'banana', 'cherry'];
console.log(myArray[1]); // Output: bananaCommon Practices and Best Practices#
Common Practices#
- Explicit Typing: Always explicitly type your objects and interfaces whenever possible. This makes the code more readable and easier to maintain.
- Use Interfaces for Object Shapes: Use interfaces to define the shape of objects. This helps in enforcing a specific structure for objects throughout the codebase.
Best Practices#
- Keep Interfaces Small and Focused: Interfaces should have a single responsibility. Avoid creating large, monolithic interfaces that do too many things.
- Leverage Optional and Readonly Properties: Use optional properties when a value may or may not be present, and readonly properties when a value should not be changed after initialization.
Conclusion#
In this quiz, we've covered various aspects of working with objects and interfaces in TypeScript. By understanding the correct syntax, common practices, and best practices, you can write more robust and maintainable TypeScript code. Remember to practice these concepts in your own projects to solidify your understanding.