You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
- TS also ships with a `Parameters` utility type for extracting the parameters of a function
1540
1541
- for anything more "custom", the `infer` keyword is the basic building block for this, but takes a bit of getting used to. Look at the source code for the above utility types, and [this example](https://twitter.com/mgechev/status/1211030455224422401?s=20) to get the idea.
1541
1542
1543
+
## The Types I need don't exist!
1544
+
1545
+
What's more annoying than modules with unexported types? Modules that are **untyped**!
1546
+
1547
+
Fret not! It's just a simple two step process.
1548
+
1549
+
- Create a new type declaration file, say `typedec.d.ts`– if you don't already have one. Ensure that the path to file is resolvable by Typescript. To do so, check the `include` array in the `tsconfig.json` file at the root of your directory.
1550
+
1551
+
```json
1552
+
// inside tsconfig.json
1553
+
{
1554
+
...
1555
+
"include": [
1556
+
"src"// automatically resolves if path to declaration is src/typedec.d.ts
1557
+
],
1558
+
...
1559
+
}
1560
+
```
1561
+
1562
+
- Add the `declare` syntax for your desired module, say `my-untyped-module`– to the declaration file.
1563
+
1564
+
```ts
1565
+
// inside typedec.d.ts
1566
+
declaremodule"my-untyped-module";
1567
+
```
1568
+
1569
+
This one-line alone is enough if you just need it to work without errors. If you need to, you can include your type definitions inferred from the untyped module's source or docs within curly braces following this declaration.
1570
+
1571
+
If you're working with untyped class components in React, you can also checkout this [short post](https://templecoding.com/blog/2016/03/31/creating-typescript-typings-for-existing-react-components) as a reference.
1572
+
1542
1573
# Troubleshooting Handbook: Images and other non-TS/TSX files
1543
1574
1544
1575
Use [declaration merging](https://www.typescriptlang.org/docs/handbook/declaration-merging.html):
Copy file name to clipboardExpand all lines: docs/basic/troubleshooting/types.md
+158-1
Original file line number
Diff line number
Diff line change
@@ -8,7 +8,7 @@ sidebar_label: Types
8
8
9
9
Facing weird type errors? You aren't alone. This is the hardest part of using TypeScript with React. Be patient - you are learning a new language after all. However, the more you get good at this, the less time you'll be working _against_ the compiler and the more the compiler will be working _for_ you!
10
10
11
-
Try to avoid typing with `any` as much as possible to experience the full benefits of typescript. Instead, let's try to be familiar with some of the common strategies to solve these issues.
11
+
Try to avoid typing with `any` as much as possible to experience the full benefits of TypeScript. Instead, let's try to be familiar with some of the common strategies to solve these issues.
12
12
13
13
## Union Types and Type Guarding
14
14
@@ -367,3 +367,160 @@ let baz2: SubIsntType2 = {
367
367
368
368
- TS also ships with a `Parameters` utility type for extracting the parameters of a function
369
369
- for anything more "custom", the `infer` keyword is the basic building block for this, but takes a bit of getting used to. Look at the source code for the above utility types, and [this example](https://twitter.com/mgechev/status/1211030455224422401?s=20) to get the idea. Basarat [also has a good video on `infer`](https://www.youtube.com/watch?v=ijK-1R-LFII&list=PLYvdvJlnTOjF6aJsWWAt7kZRJvzw-en8B&index=3&t=0s).
370
+
371
+
## The Types I need don't exist!
372
+
373
+
What's more annoying than modules with unexported types? Modules that are **untyped**!
374
+
375
+
Fret not! There are more than a couple of ways in which you can solve this problem.
376
+
377
+
A **lazier** way would be to create a new type declaration file, say `typedec.d.ts`– if you don't already have one. Ensure that the path to file is resolvable by TypeScript by checking the `include` array in the `tsconfig.json` file at the root of your directory.
378
+
379
+
```json
380
+
// inside tsconfig.json
381
+
{
382
+
// ...
383
+
"include": [
384
+
"src"// automatically resolves if the path to declaration is src/typedec.d.ts
385
+
]
386
+
// ...
387
+
}
388
+
```
389
+
390
+
Within this file, add the `declare` syntax for your desired module, say `my-untyped-module`– to the declaration file:
391
+
392
+
```ts
393
+
// inside typedec.d.ts
394
+
declaremodule"my-untyped-module";
395
+
```
396
+
397
+
This one-liner alone is enough if you just need it to work without errors. A even hackier, write-once-and-forget way would be to use `"*"` instead which would then apply the `Any` type for all existing and future untyped modules.
398
+
399
+
This solution works well as a workaround if you have less than a couple untyped modules. Anything more, you now have a ticking type-bomb in your hands. The only way of circumventing this problem would be to define the missing types for those untyped modules as explained in the following sections.
400
+
401
+
### Typing Exported Hooks
402
+
403
+
Typing Hooks is just like typing pure functions.
404
+
405
+
The following steps work under two assumptions:
406
+
407
+
- You have already created a type declaration file as stated earlier in the section.
408
+
- You have access to the source code - specifically the code that directly exports the functions you will be using. In most cases, it would be housed in an `index.js` file.
409
+
Typically you need a minimum of **two** type declarations (one for **Input Prop** and the other for **Return Prop**) to define a hook completely. Suppose the hook you wish to type follows the following structure,
410
+
411
+
```js
412
+
// ...
413
+
constuseUntypedHook= (prop) => {
414
+
// some processing happens here
415
+
return {
416
+
/* ReturnProps */
417
+
};
418
+
};
419
+
exportdefaultuseUntypedHook;
420
+
```
421
+
422
+
then, your type declaration should most likely follow the following syntax.
423
+
424
+
```ts
425
+
declaremodule'use-untyped-hook' {
426
+
export interface InputProps { ... } // type declaration for prop
427
+
export interface ReturnProps { ... } // type declaration for return props
428
+
export default function useUntypedHook(
429
+
prop:InputProps
430
+
// ...
431
+
):ReturnProps;
432
+
}
433
+
```
434
+
435
+
<details>
436
+
<summary>
437
+
438
+
For instance, the [useDarkMode hook](https://github.com/donavon/use-dark-mode) exports the functions that follows a similar structure.
439
+
440
+
</summary>
441
+
442
+
```js
443
+
// inside src/index.js
444
+
constuseDarkMode= (
445
+
initialValue=false, // -> input props / config props to be exported
As the comments suggest, exporting these config props and return props following the aforementioned structure will result in the following type export.
470
+
471
+
```ts
472
+
declaremodule"use-dark-mode" {
473
+
/**
474
+
* A config object allowing you to specify certain aspects of `useDarkMode`
475
+
*/
476
+
export interface DarkModeConfig {
477
+
classNameDark?:string; // A className to set "dark mode". Default = "dark-mode".
478
+
classNameLight?:string; // A className to set "light mode". Default = "light-mode".
479
+
element?:HTMLElement; // The element to apply the className. Default = `document.body`
480
+
onChange?: (val?:boolean) =>void; // Overide the default className handler with a custom callback.
481
+
storageKey?:string; // Specify the `localStorage` key. Default = "darkMode". Set to `null` to disable persistent storage.
482
+
storageProvider?:WindowLocalStorage; // A storage provider. Default = `localStorage`.
483
+
global?:Window; // The global object. Default = `window`.
484
+
}
485
+
/**
486
+
* An object returned from a call to `useDarkMode`.
487
+
*/
488
+
export interface DarkMode {
489
+
readonlyvalue: boolean;
490
+
enable: () =>void;
491
+
disable: () =>void;
492
+
toggle: () =>void;
493
+
}
494
+
/**
495
+
* A custom React Hook to help you implement a "dark mode" component for your application.
496
+
*/
497
+
export default function useDarkMode(
498
+
initialState?:boolean,
499
+
config?:DarkModeConfig
500
+
):DarkMode;
501
+
}
502
+
```
503
+
504
+
</details>
505
+
506
+
### Typing Exported Components
507
+
508
+
In case of typing untyped class components, there's almost no difference in approach except for the fact that after declaring the types, you export the extend the type using `classUntypedClassComponentextendsReact.Component<UntypedClassComponentProps, any> {}` where `UntypedClassComponentProps` holds the type declaration.
509
+
510
+
For instance, [sw-yx's Gist on React Router 6 types](https://gist.github.com/sw-yx/37a6a3d248c2d4031801f0d568904df8) implemented a similar method for typing the then untyped RR6.
511
+
512
+
```ts
513
+
declaremodule"react-router-dom" {
514
+
import * asReactfrom'react';
515
+
// ...
516
+
type NavigateProps<T> = {
517
+
to: string|number,
518
+
replace?:boolean,
519
+
state?:T
520
+
}
521
+
//...
522
+
export class Navigate<T=any>extendsReact.Component<NavigateProps<T>>{}
523
+
// ...
524
+
```
525
+
526
+
For more information on creating type definitions for class components, you can refer to this [post](https://templecoding.com/blog/2016/03/31/creating-typescript-typings-for-existing-react-components) for reference.
0 commit comments