### TypeScript Type Inference Examples Source: https://github.com/ts-dev-inc/ts.dev/blob/main/style.md Demonstrates how TypeScript infers types for variables and initializations. It highlights when type annotations are unnecessary and can even be detrimental to readability. Includes examples for simple literals and complex types like Sets. ```typescript const x = 15; // Type inferred. ``` ```typescript const x: boolean = true; // Bad: 'boolean' here does not aid readability ``` ```typescript // Bad: 'Set' is trivially inferred from the initialization const x: Set = new Set(); ``` ```typescript const x = new Set(); ``` -------------------------------- ### TypeScript Import Style Guide Example Source: https://github.com/ts-dev-inc/ts.dev/blob/main/style.md Illustrates the recommended naming convention for module namespace imports (lowerCamelCase) and file names (snake_case) in TypeScript. It also notes exceptions for commonly used libraries like jQuery and Three.js. ```typescript import * as fooBar from "./foo_bar"; ``` -------------------------------- ### Implementing Getters and Setters in TypeScript Source: https://github.com/ts-dev-inc/ts.dev/blob/main/style.md Provides an example of using getters and setters (accessors) for class members in TypeScript. It emphasizes that getter methods should be pure functions and demonstrates how accessors can hide internal implementation details. ```typescript class Foo { constructor(private readonly someService: SomeService) {} get someMember(): string { return this.someService.someVariable; } set someMember(newValue: string) { this.someService.someVariable = newValue; } } ``` ```typescript class Foo { private wrappedBar = ""; get bar() { return this.wrappedBar || "bar"; } set bar(wrapped: string) { this.wrappedBar = wrapped.trim(); } } ``` -------------------------------- ### Documenting Function Implementations in TypeScript Source: https://github.com/ts-dev-inc/ts.dev/blob/main/style.md Demonstrates documenting a method's purpose and parameters within its class definition in TypeScript using JSDoc. Includes an example of a TODO comment for future improvements. ```typescript /** An ancient {@link CoffeeBrewer} */ export class Percolator implements CoffeeBrewer { /** * Brews coffee. * @param amountLitres The amount to brew. Must fit the pot size! */ brew(amountLitres: number) { // This implementation creates terrible coffee, but whatever. // TODO(b/12345): Improve percolator brewing. } } ``` -------------------------------- ### TypeScript Module Import Example Source: https://github.com/ts-dev-inc/ts.dev/blob/main/style.md Demonstrates using a module import in TypeScript to access symbols from a module. This approach namespaces all imported symbols under the module name, which can improve readability and reduce name collisions. ```typescript // Bad: overlong import statement of needlessly namespaced names. import {TableViewItem, TableViewHeader, TableViewRow, TableViewModel, TableViewRenderer} from './tableview'; let item: TableViewItem = ...; ``` ```typescript // Better: use the module for namespacing. import * as tableview from './tableview'; let item: tableview.Item = ...; ``` -------------------------------- ### TypeScript React Component Naming Example (Good) Source: https://github.com/ts-dev-inc/ts.dev/blob/main/style.md Illustrates the correct naming convention (`UpperCamelCase`) for React components in TypeScript, whether implemented as functions or classes, to ensure compatibility with JSX. ```typescript function GoLink(props: GoLinkProps) { return ...; } class MyDialog extends React.Component { ... } ``` -------------------------------- ### TypeScript React Component Naming Example (Bad) Source: https://github.com/ts-dev-inc/ts.dev/blob/main/style.md Shows an incorrect example of naming a React component with a lowercase first letter, which will cause issues with JSX as the transpiler cannot distinguish it from standard HTML tags. ```typescript // Lowercased functions cannot be used as JSX elements because the // transpiler cannot distinguish them from HTML tags. function goLink(props: GoLinkProps) { return ...; } ``` -------------------------------- ### TypeScript Module Import Paths Source: https://github.com/ts-dev-inc/ts.dev/blob/main/style.md TypeScript code should use paths to import other TypeScript code. This example demonstrates valid relative and root-based import paths. ```typescript import { Symbol1 } from "google3/path/from/root"; import { Symbol2 } from "../parent/file"; import { Symbol3 } from "./sibling"; ``` -------------------------------- ### NPM Build Scripts for Static Site Development Source: https://context7.com/ts-dev-inc/ts.dev/llms.txt Defines scripts in package.json for cleaning build artifacts, starting a development server with live reload, building the production static site, and compiling TypeScript. Includes commands for cleaning, starting, building, and watching TypeScript. ```json { "scripts": { "clean": "del-cli ./_site & del-cli ./_tmp & del-cli ./js", "start": "npm run watch:ts & eleventy --serve & postcss styles/tailwind.css --o _tmp/style.css --watch", "build": "npm run build:ts && ELEVENTY_PRODUCTION=true eleventy && NODE_ENV=production postcss styles/tailwind.css --o _site/style.css && cleancss _site/style.css -o _site/style.css", "build:ts": "tsc --outDir ./js", "watch:ts": "npm run build:ts -- --watch" } } ``` ```bash # Start development server with live reload npm start # This runs TypeScript compiler in watch mode, Eleventy dev server, and PostCSS watcher # Build for production npm run build # Compiles TypeScript, builds static site with minification, processes and minifies CSS # Clean build artifacts npm clean ``` -------------------------------- ### Avoiding Redundant Comments in TypeScript Source: https://github.com/ts-dev-inc/ts.dev/blob/main/style.md Provides examples of redundant and informative comments in TypeScript. It advises against comments that merely restate parameter names and types, suggesting they are only required when adding extra information. ```typescript /** * POSTs the request to start coffee brewing. * @param amountLitres The amount to brew. Must fit the pot size! */ brew(amountLitres: number, logger: Logger) { // ... } ``` -------------------------------- ### Implement Interactive Guide Navigation with IntersectionObserver (TypeScript) Source: https://context7.com/ts-dev-inc/ts.dev/llms.txt This TypeScript code implements interactive navigation for a style guide. It uses the `IntersectionObserver` API to automatically highlight the active section in the table of contents (TOC) as the user scrolls. It also adds functionality for manual TOC link clicks and a clipboard copy feature for section headers. Dependencies include DOM manipulation methods and the `IntersectionObserver` API. ```typescript function loaded() { const options = { root: document.querySelector(".sg-container"), rootMargin: `0px 0px -90% 0px`, threshold: 0.5, }; const tocElement = document.querySelector(".toc")!; const tocAnchors = tocElement.querySelectorAll("a")!; const headers = document.querySelectorAll("h2, h3, h4"); // Handle manual TOC clicks tocAnchors.forEach((anchor) => { anchor.addEventListener("click", () => { tocAnchors.forEach((other) => { if (other.classList.contains("active")) { other.classList.remove("active"); } }); anchor.classList.add("active"); }); }); // Observe headers for automatic TOC highlighting const observer = new IntersectionObserver((entries, observer) => { entries.forEach((entry) => { if (entry.isIntersecting) { const href = entry.target.getElementsByTagName("a")[0].href; for (const navItem of tocAnchors) { if (navItem.classList.contains("active")) { navItem.classList.remove("active"); } if (navItem.href === href) { navItem.classList.add("active"); navItem.scrollIntoView({ behavior: "smooth", block: "center" }); history.pushState({}, document.title, href); } } } }); }, options); headers.forEach((header) => { observer.observe(header); // Add clipboard copy link to headers const link = document.createElement("a"); link.href = "#" + header.id; link.classList.add("clipboard"); const img = document.createElement('img'); img.style.display = "inline-block"; img.style.height = "24px"; img.src = "/svg/link.svg"; img.alt = "copy link to the clipboard"; link.appendChild(img); link.addEventListener("click", (event) => { event.preventDefault(); navigator.clipboard.writeText(link.href).then(() => { const toast = document.createElement("span"); toast.classList.add("clipboard-confirm"); toast.innerText = "Copied"; link.append(toast); setTimeout(() => toast.remove(), 1000); }); }); header.append(link); }); } window.addEventListener("load", loaded); ``` -------------------------------- ### TypeScript Array Type Syntax: Bad Practice Source: https://github.com/ts-dev-inc/ts.dev/blob/main/style.md Highlights less preferred syntaxes for declaring array types in TypeScript. These examples are either longer than necessary or can be harder to read. ```typescript const f: Array; // the syntax sugar is shorter const g: ReadonlyArray; const h: { n: number; s: string }[]; // the braces/parens make it harder to read const i: (string | number)[]; const j: readonly (string | number)[]; ``` -------------------------------- ### Nunjucks Home Page Template Source: https://context7.com/ts-dev-inc/ts.dev/llms.txt Example of a home page template that utilizes the base marketing layout. It defines the title and the main content section, including a hero article with a heading and an image. ```nunjucks கொள்ள{# index.njk - Home page #} --- layout: layout.njk title: TS.dev --- {% block content %}

Top Software Development

{% endblock %} ``` -------------------------------- ### TypeScript Import Statement Variants Source: https://github.com/ts-dev-inc/ts.dev/blob/main/style.md This snippet showcases the different types of import statements available in ES6 and TypeScript. It provides examples for module, destructuring, default, and side-effect imports, along with guidance on when each type should be used. ```typescript // Good: choose between two options as appropriate (see below). import * as ng from "@angular/core"; import { Foo } from "./foo"; // Only when needed: default imports. import Button from "Button"; // Sometimes needed to import libraries for their side effects: import "jasmine"; import "@polymer/paper-button"; ``` -------------------------------- ### TypeScript Destructuring Import Example Source: https://github.com/ts-dev-inc/ts.dev/blob/main/style.md Illustrates using destructuring imports in TypeScript to import specific symbols directly into the local scope. This method is useful for commonly used symbols, leading to more concise code. ```typescript // Better: give local names for these common functions. import {describe, it, expect} from './testing'; describe('foo', () => { it('bar', () => { expect(...); expect(...); }); }); ... ``` -------------------------------- ### TypeScript Destructuring Assignment Example Source: https://github.com/ts-dev-inc/ts.dev/blob/main/style.md Demonstrates how to use destructuring assignment with extra commas to ignore intermediate elements from an array or tuple in TypeScript. ```typescript const [a, , b] = [1, 5, 10]; // a <- 1, b <- 10 ``` -------------------------------- ### Correct Constructor Calls in TypeScript Source: https://github.com/ts-dev-inc/ts.dev/blob/main/style.md Demonstrates the correct way to instantiate classes using parentheses for constructor calls, even when no arguments are passed. It also highlights when default constructors are sufficient and when explicit constructors are necessary. ```typescript const x = new Foo(); ``` ```typescript class DefaultConstructor {} class ParameterProperties { constructor(private myService) {} } class ParameterDecorators { constructor(@SideEffectDecorator myService) {} } class NoInstantiation { private constructor() {} } ``` -------------------------------- ### Correct Decorator Placement in TypeScript Source: https://github.com/ts-dev-inc/ts.dev/blob/main/style.md When using decorators in TypeScript, they must immediately precede the symbol they decorate, with no empty lines in between. This example shows correct placement for class and field decorators. ```typescript /** JSDoc comments go before decorators */ @Component({...}) // Note: no empty line after the decorator. class MyComp { @Input() myField: string; // Decorators on fields may be on the same line... @Input() myOtherField: string; // ... or wrap. } ``` -------------------------------- ### TypeScript Indexable Type: Good Practice Source: https://github.com/ts-dev-inc/ts.dev/blob/main/style.md Demonstrates the correct way to define an indexable type in TypeScript, providing a meaningful label for the key. This improves code readability and documentation. ```typescript const users: {[userName: string]: number} = ...; ``` -------------------------------- ### Documenting Parameter Properties in TypeScript Source: https://github.com/ts-dev-inc/ts.dev/blob/main/style.md Demonstrates how to document parameter properties in TypeScript constructors using JSDoc's `@param` annotation. This documentation is displayed in editors on constructor calls and property accesses. ```typescript /** This class demonstrates how parameter properties are documented. */ class ParamProps { /** * @param percolator The percolator used for brewing. * @param beans The beans to brew. */ constructor( private readonly percolator: Percolator, private readonly beans: CoffeeBean[] ) {} } ``` ```typescript /** This class demonstrates how ordinary fields are documented. */ class OrdinaryClass { /** The bean that will be used in the next call to brew(). */ nextBean: CoffeeBean; constructor(initialBean: CoffeeBean) { this.nextBean = initialBean; } } ``` -------------------------------- ### TypeScript Structural Typing: Function Argument Example Source: https://github.com/ts-dev-inc/ts.dev/blob/main/style.md Shows how TypeScript's structural typing affects function calls. The example highlights how explicit type annotations on function parameters and variables can lead to type errors at the most convenient location. ```typescript interface Animal { sound: string; name: string; } function makeSound(animal: Animal) {} /** * 'cat' has an inferred type of '{sound: string}' */ const cat = { sound: "meow", }; /** * 'cat' does not meet the type contract required for the function, so the * TypeScript compiler errors here, which may be very far from where 'cat' is * defined. */ makeSound(cat); /** * Horse has a structural type and the type error shows here rather than the * function call. 'horse' does not meet the type contract of 'Animal'. */ const horse: Animal = { sound: "niegh", }; const dog: Animal = { sound: "bark", name: "MrPickles", }; makeSound(dog); makeSound(horse); ``` -------------------------------- ### Placing JSDoc Before Decorators in TypeScript Source: https://github.com/ts-dev-inc/ts.dev/blob/main/style.md Illustrates the correct placement of JSDoc comments relative to decorators in TypeScript classes. JSDoc should precede decorators for proper documentation rendering. ```typescript /** Component that prints "bar". */ @Component({ selector: "foo", template: "bar", }) export class FooComponent {} ``` -------------------------------- ### Event Handlers with Arrow Functions in TypeScript Source: https://github.com/ts-dev-inc/ts.dev/blob/main/style.md Explains the appropriate use of arrow functions for event handlers in TypeScript, covering scenarios where handlers need to be uninstalled and when they don't. ```TypeScript // Event handlers may be anonymous functions or arrow function properties. class Component { onAttached() { // The event is emitted by this class, no need to uninstall. this.addEventListener("click", () => { this.listener(); }); // this.listener is a stable reference, we can uninstall it later. window.addEventListener("onbeforeunload", this.listener); } onDetached() { // The event is emitted by window. If we don't uninstall, this.listener will // keep a reference to `this` because it's bound, causing a memory leak. window.removeEventListener("onbeforeunload", this.listener); } // An arrow function stored in a property is bound to `this` automatically. private listener = () => { confirm("Do you want to exit the page?"); }; } // Binding listeners creates a temporary reference that prevents uninstalling. class Component { onAttached() { // This creates a temporary reference that we won't be able to uninstall window.addEventListener("onbeforeunload", this.listener.bind(this)); } onDetached() { // This bind creates a different reference, so this line does nothing. window.removeEventListener("onbeforeunload", this.listener.bind(this)); } private listener() { confirm("Do you want to exit the page?"); } } ``` -------------------------------- ### TypeScript Constant Declaration Example (Class) Source: https://github.com/ts-dev-inc/ts.dev/blob/main/style.md Demonstrates declaring constants as `static readonly` properties within a TypeScript class. This is suitable for values that are fixed throughout the program's lifetime and intended to be immutable. ```typescript class Foo { private static readonly MY_SPECIAL_NUMBER = 5; bar() { return 2 * Foo.MY_SPECIAL_NUMBER; } } ``` -------------------------------- ### TypeScript Constant Declaration Example (Object) Source: https://github.com/ts-dev-inc/ts.dev/blob/main/style.md Shows how to declare constants using `const` in `CONSTANT_CASE` for values intended not to be changed, even if technically mutable in JavaScript. This serves as a clear signal to developers not to modify the value. ```typescript const UNIT_SUFFIXES = { milliseconds: "ms", seconds: "s", }; // Even though per the rules of JavaScript UNIT_SUFFIXES is // mutable, the uppercase shows users to not modify it. ``` -------------------------------- ### File Encoding and Character Representation in TypeScript Source: https://github.com/ts-dev-inc/ts.dev/blob/main/style.md Illustrates how to handle non-ASCII and non-printable characters in TypeScript source files. It shows the preferred method of using actual Unicode characters for readability and escape sequences for non-printable characters with explanatory comments. ```typescript // Perfectly clear, even without a comment. const units = "μs"; // Use escapes for non-printable characters. const output = "\ufeff" + content; // byte order mark ``` ```typescript // Hard to read and prone to mistakes, even with the comment. const units = "\u03bcs"; // Greek letter mu, 's' // The reader has no idea what this is. const output = "\ufeff" + content; ``` -------------------------------- ### Documentation Placement for Decorators in TypeScript Source: https://github.com/ts-dev-inc/ts.dev/blob/main/style.md Shows the incorrect placement of JSDoc comments between a decorator and the decorated statement in TypeScript, emphasizing that documentation should always come before decorators. ```typescript @Component({ selector: "foo", template: "bar", }) /** Component that prints "bar". */ export class FooComponent {} ``` -------------------------------- ### TypeScript Alternatives to 'any' Type Source: https://github.com/ts-dev-inc/ts.dev/blob/main/style.md Illustrates how to replace the 'any' type in TypeScript with more specific and safer alternatives, including declared interfaces for server-side JSON, type aliases for repetitive types, inline object types for complex returns, and generic types. ```typescript // Use declared interfaces to represent server-side JSON. declare interface MyUserJson { name: string; email: string; } // Use type aliases for types that are repetitive to write. type MyType = number | string; // Or use inline object types for complex returns. function getTwoThings(): { something: number; other: string } { // ... return { something, other }; } // Use a generic type, where otherwise a library would say `any` to represent // they don't care what type the user is operating on (but note "Return type // only generics" below). function nicestElement(items: T[]): T { // Find the nicest element in items. // Code can also put constraints on T, e.g. . } ``` -------------------------------- ### TypeScript Array Type Syntax: Good Practice Source: https://github.com/ts-dev-inc/ts.dev/blob/main/style.md Shows the preferred, concise syntax for declaring array types in TypeScript. Using `T[]` is generally recommended for simple types and `Array` for more complex ones. ```typescript const a: string[]; const b: readonly string[]; const c: ns.MyObj[]; const d: Array; const e: ReadonlyArray; ``` -------------------------------- ### Arrow Functions as Properties in TypeScript Classes Source: https://github.com/ts-dev-inc/ts.dev/blob/main/style.md Illustrates the correct and incorrect ways to use arrow functions as properties in TypeScript classes, focusing on 'this' context preservation and potential confusion. ```TypeScript class DelayHandler { constructor() { // Problem: `this` is not preserved in the callback. `this` in the callback // will not be an instance of DelayHandler. setTimeout(this.patienceTracker, 5000); } private patienceTracker() { this.waitedPatiently = true; } } // Arrow functions usually should not be properties. class DelayHandler { constructor() { // Bad: this code looks like it forgot to bind `this`. setTimeout(this.patienceTracker, 5000); } private patienceTracker = () => { this.waitedPatiently = true; }; } // Explicitly manage `this` at call time. class DelayHandler { constructor() { // Use anonymous functions if possible. setTimeout(() => { this.patienceTracker(); }, 5000); } private patienceTracker() { this.waitedPatiently = true; } } ``` -------------------------------- ### Rebinding 'this' with Arrow Functions in TypeScript Source: https://github.com/ts-dev-inc/ts.dev/blob/main/style.md Demonstrates how to correctly rebind the 'this' pointer in TypeScript event handlers using arrow functions or explicit parameters to avoid common pitfalls. ```TypeScript function clickHandler() { // Bad: what's `this` in this context? this.textContent = "Hello"; } // Bad: the `this` pointer reference is implicitly set to document.body. document.body.onclick = clickHandler; // Good: explicitly reference the object from an arrow function. document.body.onclick = () => { document.body.textContent = "hello"; }; // Alternatively: take an explicit parameter const setTextFn = (e: HTMLElement) => { e.textContent = "hello"; }; document.body.onclick = setTextFn.bind(null, document.body); ``` -------------------------------- ### Utilizing Parameter Properties in TypeScript Constructors Source: https://github.com/ts-dev-inc/ts.dev/blob/main/style.md Shows how to use TypeScript's parameter properties to declare and initialize class members directly in the constructor signature. This reduces boilerplate code compared to traditional assignment within the constructor body. ```typescript class Foo { constructor(private readonly barService: BarService) {} } ``` -------------------------------- ### Using `unknown` for Type Safety in TypeScript Source: https://github.com/ts-dev-inc/ts.dev/blob/main/style.md Demonstrates the safe use of the `unknown` type in TypeScript. `unknown` is preferred over `any` as it prevents arbitrary property access without type narrowing or casting, enhancing type safety. ```typescript // Can assign any value (including null or undefined) into this but cannot // use it without narrowing the type or casting. const val: unknown = value; ``` ```typescript const danger: any = value; /* result of an arbitrary expression */ danger.whoops(); // This access is completely unchecked! ``` -------------------------------- ### Tuple Types for Pair Representation in TypeScript Source: https://github.com/ts-dev-inc/ts.dev/blob/main/style.md Illustrates using tuple types in TypeScript as a safer and more idiomatic alternative to defining an `interface` for simple pairs. It shows how to define and consume tuple types for function return values. ```typescript interface Pair { first: string; second: string; } function splitInHalf(input: string): Pair { ... return {first: x, second: y}; } ``` ```typescript function splitInHalf(input: string): [string, string] { ... return [x, y]; } // Use it like: const [leftHalf, rightHalf] = splitInHalf('my string'); ``` -------------------------------- ### Avoid Namespaces and require() in TypeScript Source: https://github.com/ts-dev-inc/ts.dev/blob/main/style.md TypeScript code must use ES6 modules (imports and exports) and avoid the `namespace` construct and `require()` for imports. This snippet illustrates disallowed patterns. ```typescript // Bad: do not use namespaces: namespace Rocket { function launch() { ... } } // Bad: do not use /// // Bad: do not use require() import x = require('mydep'); ``` -------------------------------- ### Inline Comments for Function Parameters in TypeScript Source: https://github.com/ts-dev-inc/ts.dev/blob/main/style.md Shows how to document function parameters at call sites using inline block comments. It also suggests using named parameters with object literals and destructuring for better readability. ```typescript // Inline block comments for parameters that'd be hard to understand: new Percolator().brew(/* amountLitres= */ 5); // Also consider using named arguments and destructuring parameters (in brew's declaration): new Percolator().brew({ amountLitres: 5 }); ``` -------------------------------- ### Spread Operator Usage for Object/Array Copying in TypeScript Source: https://github.com/ts-dev-inc/ts.dev/blob/main/style.md Demonstrates the use of the spread operator (`...`) in TypeScript for creating shallow copies of objects and arrays. It shows how properties are merged and how later values override earlier ones in object spreads. ```typescript const foo = { num: 1, }; const foo2 = { ...foo, num: 5, }; const foo3 = { num: 5, ...foo, }; foo2.num === 5; foo3.num === 1; ``` ```typescript const foo = shouldUseFoo ? { num: 7 } : {}; const bar = { num: 5, ...foo }; const fooStrings = ["a", "b", "c"]; const ids = [...fooStrings, "d", "e"]; ``` -------------------------------- ### Safe Object Iteration in TypeScript Source: https://github.com/ts-dev-inc/ts.dev/blob/main/style.md Demonstrates safe ways to iterate over object properties in TypeScript, avoiding prototype chain pollution. It includes methods using `hasOwnProperty` and `Object.keys`/`Object.entries` for robust iteration. ```typescript for (const x in someObj) { if (!someObj.hasOwnProperty(x)) continue; // now x was definitely defined on someObj } for (const x of Object.keys(someObj)) { // note: for _of_! // now x was definitely defined on someObj } for (const [key, value] of Object.entries(someObj)) { // note: for _of_! // now key was definitely defined on someObj } ``` -------------------------------- ### Suppressing `any` Lint Warnings in TypeScript Tests Source: https://github.com/ts-dev-inc/ts.dev/blob/main/style.md Shows how to legitimately use the `any` type in TypeScript tests, particularly for mock objects. It includes suppressing `tslint` warnings with comments explaining the justification for using `any`. ```typescript // This test only needs a partial implementation of BookService, and if // we overlooked something the test will fail in an obvious way. // This is an intentionally unsafe partial mock // tslint:disable-next-line:no-any const mockBookService = ({ get() { return mockBook; }, } as any) as BookService; // Shopping cart is not used in this test // tslint:disable-next-line:no-any const component = new MyComponent( mockBookService, /* unused ShoppingCart */ null as any ); ``` -------------------------------- ### TypeScript Indexable Type: Bad Practice Source: https://github.com/ts-dev-inc/ts.dev/blob/main/style.md Illustrates a less informative way to define an indexable type in TypeScript, using a generic 'key' label. This can make the code less clear about the intended use of the keys. ```typescript const users: {[key: string]: number} = ...; ``` -------------------------------- ### Initializing Class Members at Declaration in TypeScript Source: https://github.com/ts-dev-inc/ts.dev/blob/main/style.md Illustrates initializing class members at the point of declaration rather than within the constructor. This can simplify class definitions and sometimes eliminate the need for an explicit constructor. ```typescript class Foo { private readonly userList: string[] = []; } ``` -------------------------------- ### TypeScript Structural Typing: Good Practice Source: https://github.com/ts-dev-inc/ts.dev/blob/main/style.md Demonstrates the correct way to declare an object with a specific structural type in TypeScript. Explicitly annotating the type ensures more precise type checking and error reporting at the declaration site. ```typescript const foo: Foo = { a: 123, b: "abc", }; ``` -------------------------------- ### Use Named Exports in TypeScript Source: https://github.com/ts-dev-inc/ts.dev/blob/main/style.md This snippet demonstrates the correct way to use named exports in TypeScript. Named exports allow for clearer import statements and better tooling support. Avoid default exports as they can lead to ambiguity and maintenance issues. ```typescript // Use named exports: export class Foo { ... } ``` ```typescript // Do not use default exports: export default class Foo { ... } // BAD! ``` -------------------------------- ### TypeScript Object Typing: Interface (Good Practice) Source: https://github.com/ts-dev-inc/ts.dev/blob/main/style.md Demonstrates the recommended way to define object types in TypeScript using interfaces. Interfaces are preferred for object literals due to their extensibility and better tooling support. ```typescript interface User { firstName: string; lastName: string; } ``` -------------------------------- ### Local Aliases and Class Field Declarations in TypeScript Source: https://github.com/ts-dev-inc/ts.dev/blob/main/style.md Demonstrates the correct way to create local-scope aliases for existing symbols using 'const' for variables and the 'readonly' attribute for class fields, ensuring consistency with the source naming format. ```typescript const { Foo } = SomeType; const CAPACITY = 5; class Teapot { readonly BrewStateEnum = BrewStateEnum; readonly CAPACITY = CAPACITY; } ``` -------------------------------- ### TypeScript Inline Object Type Declaration Syntax Source: https://github.com/ts-dev-inc/ts.dev/blob/main/style.md Demonstrates the correct syntax for inline object type declarations in TypeScript. It specifies that commas (,) should be used as separators for members within these inline types, distinguishing them from interface declarations. ```typescript type SomeTypeAlias = { memberA: string; memberB: number; }; let someProperty: { memberC: string; memberD: number }; ``` -------------------------------- ### TypeScript Type Assertion Syntax Comparison Source: https://github.com/ts-dev-inc/ts.dev/blob/main/style.md Compares the incorrect angle-bracket syntax with the recommended 'as' syntax for type assertions in TypeScript. The 'as' syntax enforces parentheses around the assertion when accessing a member, improving clarity and safety. ```typescript // Bad: Angle bracket syntax // const x = (z).length; // const y = z.length; // Good: 'as' syntax const x = (z as Foo).length; ``` -------------------------------- ### TypeScript Strict Equality Checks Source: https://github.com/ts-dev-inc/ts.dev/blob/main/style.md Recommends using strict equality operators (`===`, `!==`) over loose equality (`==`, `!=`) to avoid error-prone type coercion. An exception is made for comparing to `null` to cover both `null` and `undefined`. ```typescript if (foo === "bar" || baz !== bam) { // All good here. } ``` ```typescript if (foo == null) { // Will trigger when foo is null or undefined. } ``` -------------------------------- ### Avoid Container Classes for Namespacing in TypeScript Source: https://github.com/ts-dev-inc/ts.dev/blob/main/style.md This snippet illustrates the anti-pattern of using container classes with static members for namespacing. Instead, export individual constants and functions directly to simplify the module's API and avoid unnecessary scope layers. ```typescript export class Container { static FOO = 1; static bar() { return 1; } } ``` ```typescript export const FOO = 1; export function bar() { return 1; } ``` -------------------------------- ### Inline Object Types for Named Properties in TypeScript Source: https://github.com/ts-dev-inc/ts.dev/blob/main/style.md Demonstrates using inline object literal types in TypeScript for function return values when defining a full interface is considered too heavyweight. This approach allows for named properties, improving readability. ```typescript function splitHostPort(address: string): {host: string, port: number} { ... } // Use it like: const address = splitHostPort(userAddress); use(address.port); // You can also get tuple-like behavior using destructuring: const {host, port} = splitHostPort(userAddress); ``` -------------------------------- ### Eleventy Configuration for Static Site Generation Source: https://context7.com/ts-dev-inc/ts.dev/llms.txt Configures Eleventy with plugins for table of contents, SCSS compilation, Markdown processing with syntax highlighting, HTML minification in production, and passthrough copy for static assets. It also includes a version shortcode for cache busting. ```javascript const htmlmin = require("html-minifier"); const markdownIt = require("markdown-it"); const markdownItAttrs = require("markdown-it-attrs"); const pluginTOC = require("eleventy-plugin-nesting-toc"); module.exports = function (eleventyConfig) { // Add table of contents plugin eleventyConfig.addPlugin(pluginTOC); // Configure SCSS compilation eleventyConfig.addTemplateFormats("scss"); eleventyConfig.addExtension("scss", { outputFileExtension: "css", compile: async function(inputContent) { let result = sass.compileString(inputContent); return async (data) => { return result.css; }; } }); // Set up watch targets for live reload eleventyConfig.addWatchTarget("./_tmp/style.css"); eleventyConfig.addWatchTarget("./js/"); // Configure Markdown with syntax highlighting eleventyConfig.setLibrary("md", markdownIt({ html: true, breaks: false, linkify: true, highlight: highlighter, }).use(markdownItAttrs, { allowedAttributes: [], })); // Minify HTML in production eleventyConfig.addTransform("htmlmin", function (content, outputPath) { if (process.env.ELEVENTY_PRODUCTION && outputPath?.endsWith(".html")) { return htmlmin.minify(content, { useShortDoctype: true, removeComments: true, collapseWhitespace: true, }); } return content; }); // Add passthrough copies for static assets eleventyConfig.addPassthroughCopy({ "./_tmp/style.css": "./style.css" }); eleventyConfig.addPassthroughCopy("svg"); eleventyConfig.addPassthroughCopy("img"); eleventyConfig.addPassthroughCopy("js"); // Add cache-busting version shortcode eleventyConfig.addShortcode("version", function () { return String(Date.now()); }); }; ``` -------------------------------- ### TypeScript Pick vs. Interface Extension for Type Subsetting Source: https://github.com/ts-dev-inc/ts.dev/blob/main/style.md Demonstrates how TypeScript's built-in `Pick` utility type can subset properties from an existing type, and shows an equivalent implementation using interface extension for potentially better readability and IDE support. ```typescript interface User { shoeSize: number; favoriteIcecream: string; favoriteChocolate: string; } // FoodPreferences has favoriteIcecream and favoriteChocolate, but not shoeSize. type FoodPreferences = Pick; interface FoodPreferences { favoriteIcecream: string; favoriteChocolate: string; } interface User extends FoodPreferences { shoeSize: number; // also includes the preferences. } ``` -------------------------------- ### TypeScript Class Initialization Source: https://github.com/ts-dev-inc/ts.dev/blob/main/style.md Recommends initializing class fields whenever possible in TypeScript to avoid the need for optional properties. This practice promotes more predictable object states by ensuring fields have a defined value from the outset, reducing the complexity associated with potentially undefined members. ```typescript class MyClass { field = ""; } ``` -------------------------------- ### Using TypeScript Visibility Annotations Instead of Private Fields Source: https://github.com/ts-dev-inc/ts.dev/blob/main/style.md Explains why native private fields ('#private') should be avoided in favor of TypeScript's visibility annotations (`private`, `public`, `protected`) due to emit size and performance regressions when down-leveled. Demonstrates the preferred approach. ```typescript class Clazz { private ident = 1; } ``` -------------------------------- ### Avoid Debugger Statements in Production TypeScript Source: https://github.com/ts-dev-inc/ts.dev/blob/main/style.md Debugger statements should not be included in production code. This snippet demonstrates the incorrect usage. ```typescript function debugMe() { debugger; } ``` -------------------------------- ### Single-Line `if` Exception in TypeScript Source: https://github.com/ts-dev-inc/ts.dev/blob/main/style.md Explains the exception to the block rule for control flow statements in TypeScript: single-line `if` statements may omit the curly braces for brevity. ```typescript if (x) x.doFoo(); ``` -------------------------------- ### Firebase Hosting Configuration Source: https://context7.com/ts-dev-inc/ts.dev/llms.txt Configures Firebase Hosting in `firebase.json` to serve the static site from the `_site` directory. It specifies the public directory and files to ignore during deployment. ```json { "hosting": { "public": "_site", "ignore": [ "firebase.json", "**/.*", "**/node_modules/**" ] } } ``` -------------------------------- ### Array Iteration Pitfalls in TypeScript Source: https://github.com/ts-dev-inc/ts.dev/blob/main/style.md Highlights the incorrect usage of `for...in` loops for iterating over arrays in TypeScript, which yields string indices instead of values and can lead to errors. ```typescript for (const x in someArray) { // x is the index! } ``` -------------------------------- ### Nunjucks Base Marketing Layout Source: https://context7.com/ts-dev-inc/ts.dev/llms.txt Defines the base layout for marketing pages, including navigation, content blocks, and footer. It extends a default layout and includes navigation links and a contact button. ```nunjucks கொள்ள{# _includes/layout.njk - Marketing page layout #} --- bodyClass: marketing --- {% extends "_includes/default.njk" %} {% block body %} {% block content %} {{ content | safe }} {% endblock %} {% endblock %} ``` -------------------------------- ### TypeScript Import Type vs. Regular Import Source: https://github.com/ts-dev-inc/ts.dev/blob/main/style.md Shows the correct way to import types in TypeScript, avoiding `import type` and `export type`. Regular imports are preferred as TypeScript tooling automatically distinguishes between type and value references and optimizes runtime loads. ```typescript // Bad: import type and export type syntax. import type { Foo } from "./foo"; export type { Bar } from "./bar"; ``` ```typescript // Good: use regular imports for types. import { Foo } from "./foo"; export { Bar } from "./bar"; ``` -------------------------------- ### Restricting Visibility in TypeScript Source: https://github.com/ts-dev-inc/ts.dev/blob/main/style.md Illustrates a scenario where the `public` modifier is incorrectly used in TypeScript. It recommends limiting symbol visibility and considering non-exported functions for private methods. ```typescript class Foo { public bar = new Bar(); // BAD: public modifier not needed constructor(public readonly baz: Baz) {} // BAD: readonly implies it's a property which defaults to public } ``` -------------------------------- ### Handling Mutable Exports in TypeScript Source: https://github.com/ts-dev-inc/ts.dev/blob/main/style.md Demonstrates how to handle mutable exports in TypeScript. Directly exporting mutable variables (`export let`) is discouraged due to potential debugging complexities, especially with re-exports. Instead, use explicit getter functions to provide controlled access to mutable values. ```typescript export let foo = 3; // In pure ES6, foo is mutable and importers will observe the value change after a second. // In TS, if foo is re-exported by a second file, importers will not see the value change. window.setTimeout(() => { foo = 4; }, 1000 /* ms */); ``` ```typescript let foo = 3; window.setTimeout(() => { foo = 4; }, 1000 /* ms */); // Use an explicit getter to access the mutable export. export function getFoo() { return foo; } ``` ```typescript function pickApi() { if (useOtherApi()) return OtherApi; return RegularApi; } export const SomeApi = pickApi(); ``` -------------------------------- ### Object Iteration Pitfalls in TypeScript Source: https://github.com/ts-dev-inc/ts.dev/blob/main/style.md Illustrates the danger of using unfiltered `for...in` loops for object iteration in TypeScript, as it can include properties from the prototype chain, leading to unexpected behavior. ```typescript for (const x in someObj) { // x could come from some parent prototype! } ``` -------------------------------- ### TypeScript Nullable Type Aliases - Best Practice Source: https://github.com/ts-dev-inc/ts.dev/blob/main/style.md Demonstrates the recommended approach for handling nullable types in TypeScript. This pattern emphasizes defining core types without nullability and using assertion functions or explicit checks to manage potentially null return values, ensuring that nulls are dealt with close to their source. ```typescript // Best type CoffeeResponse = Latte | Americano; class CoffeeService { getLatte(): CoffeeResponse { return assert(fetchResponse(), "Coffee maker is broken, file a ticket"); } } ``` -------------------------------- ### Visibility Modifiers in TypeScript Classes Source: https://github.com/ts-dev-inc/ts.dev/blob/main/style.md Demonstrates the correct usage of visibility modifiers in TypeScript. It highlights that `public` is the default and often unnecessary, while `public readonly` in constructors is a valid use case. ```typescript class Foo { bar = new Bar(); // GOOD: public modifier not needed constructor(public baz: Baz) {} // public modifier allowed } ``` -------------------------------- ### TypeScript Arrow Functions in Expressions Source: https://github.com/ts-dev-inc/ts.dev/blob/main/style.md Promotes the use of arrow functions (`=>`) over traditional `function` expressions for brevity and lexical `this` binding. Function expressions with the `function` keyword should only be used when dynamic `this` rebinding is necessary. ```typescript bar(() => { this.doSomething(); }); ``` ```typescript const receipts = books.map((b: Book) => { const receipt = payMoney(b.price); recordTransaction(receipt); return receipt; }); ``` ```typescript const longThings = myValues .filter((v) => v.length > 1000) .map((v) => String(v)); ``` -------------------------------- ### TypeScript Switch Statements with Default Case Source: https://github.com/ts-dev-inc/ts.dev/blob/main/style.md Ensures all switch statements have a default case, even if empty, to prevent unexpected fall-through behavior. Non-empty case groups cannot fall through, while empty ones can. ```typescript switch (x) { case Y: doSomethingElse(); break; default: // nothing to do. } ``` ```typescript switch (x) { case X: case Y: doSomething(); break; default: // nothing to do. } ```