Item 71: Use Module Augmentation to Improve Types

May 10, 2024 ยท View on GitHub

Things to Remember

  • Use declaration merging to improve existing APIs or disallow problematic constructs.
  • Use void or error string returns to "knock out" methods and mark them @deprecated.
  • Remember that overloads only apply at the type level. Don't make the types diverge from reality.## Code Samples
declare let apiResponse: string;

๐Ÿ’ป playground


const response = JSON.parse(apiResponse);
const cacheExpirationTime = response.lastModified + 3600;
//    ^? const cacheExpirationTime: any

๐Ÿ’ป playground


// declarations/safe-json.d.ts
interface JSON {
  parse(
    text: string,
    reviver?: (this: any, key: string, value: any) => any
  ): unknown;
}

๐Ÿ’ป playground


const response = JSON.parse(apiResponse);
//    ^? const response: unknown
const cacheExpirationTime = response.lastModified + 3600;
//                          ~~~~~~~~ response is of type 'unknown'.

๐Ÿ’ป playground


interface ApiResponse {
  lastModified: number;
}
const response = JSON.parse(apiResponse) as ApiResponse;
const cacheExpirationTime = response.lastModified + 3600;  // ok
//    ^? const cacheExpirationTime: number

๐Ÿ’ป playground


// declarations/safe-response.d.ts
interface Body {
  json(): Promise<unknown>;
}

๐Ÿ’ป playground


interface SetConstructor {
  new <T>(iterable?: Iterable<T> | null): Set<T>;
}

๐Ÿ’ป playground


// declarations/ban-set-string-constructor.d.ts:
interface SetConstructor {
  new (str: string): void;
}

๐Ÿ’ป playground


const s = new Set('abc');
//    ^? const s: void
console.log(s.has('abc'));
//            ~~~ Property 'has' does not exist on type 'void'.
const otherSet: Set<string> = s;
//    ~~~~~~~~ Type 'void' is not assignable to type 'Set<string>'.

๐Ÿ’ป playground


interface SetConstructor {
  /** @deprecated */
  new (str: string): 'Error! new Set(string) is banned.';
}

const s = new Set('abc');
//    ^? const s: "Error! new Set(string) is banned."

๐Ÿ’ป playground