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
Copy file name to clipboardExpand all lines: README.md
+137-10
Original file line number
Diff line number
Diff line change
@@ -1544,31 +1544,158 @@ let baz2: SubIsntType2 = {
1544
1544
1545
1545
What's more annoying than modules with unexported types? Modules that are **untyped**!
1546
1546
1547
-
Fret not! It's just a simple two step process.
1547
+
Fret not! There are more than a couple of ways in which you can solve this problem.
1548
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.
1549
+
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.
1550
1550
1551
1551
```json
1552
1552
// inside tsconfig.json
1553
1553
{
1554
-
...
1555
-
"include": [
1556
-
"src"// automatically resolves if path to declaration is src/typedec.d.ts
1557
-
],
1558
-
...
1554
+
//...
1555
+
"include": [
1556
+
"src"// automatically resolves if the path to declaration is src/typedec.d.ts
1557
+
]
1558
+
//...
1559
1559
}
1560
1560
```
1561
1561
1562
-
- Add the `declare` syntax for your desired module, say `my-untyped-module`– to the declaration file.
1562
+
Within this file, add the `declare` syntax for your desired module, say `my-untyped-module`– to the declaration file:
1563
1563
1564
1564
```ts
1565
1565
// inside typedec.d.ts
1566
1566
declaremodule"my-untyped-module";
1567
1567
```
1568
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.
1569
+
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.
1570
+
1571
+
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.
1572
+
1573
+
### Typing Exported Hooks
1574
+
1575
+
Typing Hooks is just like typing pure functions.
1576
+
1577
+
The following steps work under two assumptions:
1578
+
1579
+
- You have already created a type declaration file as stated earlier in the section.
1580
+
- 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.
1581
+
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,
1582
+
1583
+
```js
1584
+
// ...
1585
+
constuseUntypedHook= (prop) => {
1586
+
// some processing happens here
1587
+
return {
1588
+
/* ReturnProps */
1589
+
};
1590
+
};
1591
+
exportdefaultuseUntypedHook;
1592
+
```
1593
+
1594
+
then, your type declaration should most likely follow the following syntax.
1595
+
1596
+
```ts
1597
+
declaremodule'use-untyped-hook' {
1598
+
export interface InputProps { ... } // type declaration for prop
1599
+
export interface ReturnProps { ... } // type declaration for return props
1600
+
export default function useUntypedHook(
1601
+
prop:InputProps
1602
+
// ...
1603
+
):ReturnProps;
1604
+
}
1605
+
```
1606
+
1607
+
<details>
1608
+
<summary>
1609
+
1610
+
For instance, the [useDarkMode hook](https://github.com/donavon/use-dark-mode) exports the functions that follows a similar structure.
1611
+
1612
+
</summary>
1613
+
1614
+
```js
1615
+
// inside src/index.js
1616
+
constuseDarkMode= (
1617
+
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.
1642
+
1643
+
```ts
1644
+
declaremodule"use-dark-mode" {
1645
+
/**
1646
+
* A config object allowing you to specify certain aspects of `useDarkMode`
1647
+
*/
1648
+
export interface DarkModeConfig {
1649
+
classNameDark?:string; // A className to set "dark mode". Default = "dark-mode".
1650
+
classNameLight?:string; // A className to set "light mode". Default = "light-mode".
1651
+
element?:HTMLElement; // The element to apply the className. Default = `document.body`
1652
+
onChange?: (val?:boolean) =>void; // Overide the default className handler with a custom callback.
1653
+
storageKey?:string; // Specify the `localStorage` key. Default = "darkMode". Set to `null` to disable persistent storage.
1654
+
storageProvider?:WindowLocalStorage; // A storage provider. Default = `localStorage`.
1655
+
global?:Window; // The global object. Default = `window`.
1656
+
}
1657
+
/**
1658
+
* An object returned from a call to `useDarkMode`.
1659
+
*/
1660
+
export interface DarkMode {
1661
+
readonlyvalue: boolean;
1662
+
enable: () =>void;
1663
+
disable: () =>void;
1664
+
toggle: () =>void;
1665
+
}
1666
+
/**
1667
+
* A custom React Hook to help you implement a "dark mode" component for your application.
1668
+
*/
1669
+
export default function useDarkMode(
1670
+
initialState?:boolean,
1671
+
config?:DarkModeConfig
1672
+
):DarkMode;
1673
+
}
1674
+
```
1675
+
1676
+
</details>
1677
+
1678
+
### Typing Exported Components
1679
+
1680
+
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.
1681
+
1682
+
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.
1683
+
1684
+
```ts
1685
+
declaremodule"react-router-dom" {
1686
+
import * asReactfrom'react';
1687
+
// ...
1688
+
type NavigateProps<T> = {
1689
+
to: string|number,
1690
+
replace?:boolean,
1691
+
state?:T
1692
+
}
1693
+
//...
1694
+
export class Navigate<T=any>extendsReact.Component<NavigateProps<T>>{}
1695
+
// ...
1696
+
```
1570
1697
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.
1698
+
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.
1572
1699
1573
1700
# Troubleshooting Handbook: Images and other non-TS/TSX files
0 commit comments