Skip to content

docs(advanced) Correct the section about discrinated types #205

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 24 additions & 17 deletions ADVANCED.md
Original file line number Diff line number Diff line change
Expand Up @@ -511,23 +511,6 @@ You may also want to use Discriminated Unions, please check out [Expressive Reac

Here is a brief intuition for **Discriminated Union Types**:

```ts
type UserTextEvent = { value: string; target: HTMLInputElement };
type UserMouseEvent = { value: [number, number]; target: HTMLElement };
type UserEvent = UserTextEvent | UserMouseEvent;
function handle(event: UserEvent) {
if (typeof event.value === "string") {
event.value; // string
event.target; // HTMLInputElement | HTMLElement (!!!!)
return;
}
event.value; // [number, number]
event.target; // HTMLInputElement | HTMLElement (!!!!)
}
```

Even though we have narrowed based on `event.value`, the logic doesn't filter up and sideways to `event.target`. This is because a union type `UserTextEvent | UserMouseEvent` could be BOTH at once. So TypeScript needs a better hint. The solution is to use a literal type to tag each case of your union type:

```ts
type UserTextEvent = {
type: "TextEvent";
Expand All @@ -551,6 +534,30 @@ function handle(event: UserEvent) {
}
```

<details>
<summary>
Take care: TypeScript does not narrow the type of a Discriminated Union on the basis of typeof checks. The type guard has to be on the value of a key and not it's type.
</summary>

```ts
type UserTextEvent = { value: string; target: HTMLInputElement };
type UserMouseEvent = { value: [number, number]; target: HTMLElement };
type UserEvent = UserTextEvent | UserMouseEvent;
function handle(event: UserEvent) {
if (typeof event.value === "string") {
event.value; // string
event.target; // HTMLInputElement | HTMLElement (!!!!)
return;
}
event.value; // [number, number]
event.target; // HTMLInputElement | HTMLElement (!!!!)
}
```

The above example does not work as we are not checking the value of `event.value` but only it's type. Read more about it [microsoft/TypeScript#30506 (comment)](https://github.com/microsoft/TypeScript/issues/30506#issuecomment-474858198)

</details>

To streamline this you may also combine this with the concept of **User-Defined Type Guards**:

```ts
Expand Down