28
loading...
This website collects cookies to deliver better user experience
function getData({tableName: process.env.TABLE_NAME as string})
/**
* By default, TypeScript is not aware of the `Cypress` global variable available whenever the code is run in the context of a Cypress test.
* If we do not amend the global type declarations, the error has to be silenced.
*/
// @ts-expect-error
if (window.Cypress) {
window.myAPI = {
/* implementation */
};
}
Cypress
global whenever your code is run in the context of a Cypress test?d.ts
file. Depending on what I'm doing I might be adding changes to a file that already exist.process.env
type declarations to include our custom environment variables.Check what is the name of the module / interface / namespace I want to extend.
process.env
I can see that the .env
property lives on a namespace called NodeJS
. The .env
property is described by an interface called ProcessEnv
.Create corresponding d.ts
file. Depending on what I'm doing I might be adding changes to a file that already exist.
global.d.ts
. Please note that I've chosen the d.ts
file extension on purpose. It signals to my colleges that this file only contains type declarations.Augment the module / interface / namespace.
.env
property lives on a namespace called NodeJS
, I'm going to follow the merging namespaces guide from the typescript handbook.// global.d.ts
namespace NodeJS {
interface ProcessEnv {
TABLE_NAME: string;
}
}
function getData({tableName: process.env.TABLE_NAME})
window
typings so that it includes the Cypress
property.window
global variable is annotated by Window
interface and the typeof globalThis
. Let us amend the Window
interface since it's easier to do so.// global.d.ts
interface Window {
Cypress?: unknown; // Depending on your use-case you might want to be more precise here.
}
global.d.ts
file, the Window
interface from the built-in type declarations will be extended with our custom Window
interface.@ts-expect-error
comment.if (window.Cypress) {
window.myAPI = {
/* implementation */
};
}
lib-from-npm
. The library in question exposes a Component
function that renders a React component:// lib-from-npm.d.ts
declare module "lib-from-npm" {
interface Props {
// ...
}
function Component (props: Props) => import("React").ReactNode
}
// MyComponent.tsx
import { Component } from "lib-from-npm";
const MyComponent = () => {
return <Component />;
};
import("React")
statement is about. What about importing the ReactNode
using import {ReactNode} from 'react'
?// lib-from-npm.d.ts
import { ReactNode } from 'react'
declare module "lib-from-npm" {
interface Props {
// ...
}
function Component (props: Props) => ReactNode
}
// MyComponent.tsx
import { Component } from "lib-from-npm"; // TypeScript complains. Read on to learn why.
const MyComponent = () => {
return <Component />;
};
Cannot find module 'lib-from-npm' or its corresponding type declarations
TypeScript error. It seems like the type of declarations I've just written does not work, how come?Whenever the TypeScript file you are working with contains a top-level import
statement(s), TypeScript will treat this file as a module. If a file is treated as a module, type declarations within that file are contained to that file only.
import("React")
statement in the first snippet. Introduced in TypeScript 2.9, the import types feature allows me to explicitly import only type declarations for a given module without using a top-level import statement. You can read more about this feature in this excellent blog post.lib-from-npm.d.ts
file.// lib-from-npm.d.ts
declare module "lib-from-npm" {
import { ReactNode } from 'react'
// Or to be even more specific
// import type { ReactNode } from 'react';
interface Props {
// ...
}
function Component (props: Props) => ReactNode
}
lib-from-npm
module. There are no top-level import(s) statements that would make this file be treated as a module by TypeScript compiler.createRoot
API to the ReactDOM
typings. The createRoot
API is related to the concurrent rendering the React 18 plans to introduce. Please note that the typings for the alpha release of React 18 already exist and should be preferred instead of rolling your own.render
API of the ReactDOM package is defined within the ReactDOM
namespace, let us extend that namespace with the createRoot
API.// react.d.ts
namespace ReactDOM {
import * as React from "react";
interface Root {
render(children: React.ReactChild | React.ReactNodeArray): void;
unmount(): void;
}
function createRoot(
container: Element | Document | DocumentFragment | Comment
): Root;
}
d.ts
files matters. In some unfortunate circumstances, it might happen that your d.ts
file will be ignored.Whenever your d.ts
file has the same name as a ts
file, and both files live in the same directory, the type declarations defined in the d.ts
file will be ignored.
react.ts
in the same directory that the react.d.ts
file lives, the type declarations defined in the react.d.ts
file would be ignored.// react.ts
import ReactDOM from "react-dom";
ReactDOM.createRoot(); // TypeScript complains.