implements, optional parameters, and array usage—into a small “duck pond” management example. Along the way we highlight code-quality ideas such as preferring pure functions and using explicit typing when it improves clarity.
Below is the cleaned and complete TypeScript implementation used for this lesson. It demonstrates the concepts above and includes both pure and impure function examples.
-
Explicit typing vs inference
- Declaring
const duckPond: PondDuck[] = []makes it explicit that onlyPondDuckinstances can be added to that array. This is useful when the container starts empty or receives external data. - If you instead define an array from existing elements (for example,
const duckPondInferred = [daffy, donald, howard];), TypeScript will infer the element type from those items. Attempts to push a different type (e.g. a string) will produce a compile-time error. - Prefer inference when it reduces boilerplate, but favor explicit types at boundaries (empty containers, external inputs).
- Declaring
-
Pure functions vs impure functions
makeAllDucksQuack(ducks, times)follows a pure-style approach because it receives all required inputs as parameters.findDuckAndFly_impure(name)readsduckPondfrom the outer scope; it depends on external state and is therefore impure. The pure variantfindDuckAndFly(name, pond)is easier to test and reuse.
-
Interfaces and
implements- The
implements IDuckonPondDuckenforces that the class matches the interface shape (at least the specified properties), helping catch structure mismatches at compile time.
- The
-
Optional parameters and defaults
- Both
quack(times = 1)andmakeAllDucksQuack(ducks, times = 1)demonstrate default parameter values. - Optional properties on types and interfaces use the
?suffix (for example,favoriteToy?: string).
- Both
-
Small utility functions
- Utilities like
countDucksByTypehelp keep logic isolated, readable, and simple to test.
- Utilities like
Prefer pure functions when possible — functions that accept all inputs and avoid accessing or mutating external state are easier to reason about, test, and reuse.

- We modeled structured data using enums and union types, and enforced shape with interfaces.
- We implemented a class (
PondDuck) with methods and optional properties, then managed instances in an explicitly typed array. - We contrasted pure and impure designs and showed simple utility functions for common pond operations.
- Use TypeScript inference to reduce boilerplate, but declare explicit types at public or empty boundaries for safety.
- Favor small, pure utilities for clarity, reusability, and easier testing.

- Generics and reusable data structures
- Utility types (
Partial,Pick,Record, etc.) - Deeper core JavaScript concepts (closures, prototype, event loop)
- Async/await patterns and Promise handling
- Decorators and advanced class patterns