Skip to content

Add signatures that enable TypeScript type guards#4

Open
NeilRashbrook wants to merge 2 commits intobenbucksch:masterfrom
NeilRashbrook:type-guards
Open

Add signatures that enable TypeScript type guards#4
NeilRashbrook wants to merge 2 commits intobenbucksch:masterfrom
NeilRashbrook:type-guards

Conversation

@NeilRashbrook
Copy link
Copy Markdown
Contributor

This enables you to write .find((e): e is Derived => e instanceof Derived) and TypeScript will infer the type of the expression to be Derived instead of the type of the collection. (Similarly for the other methods.)

This enables you to write `.find((e): e is Derived => e instanceof Derived)` and TypeScript will infer the type of the expression to be `Derived` instead of the type of the collection. (Similarly for the other methods.)
@benbucksch
Copy link
Copy Markdown
Owner

Why would you not simply declare the collection to be Subtype (= Derived in your example)?

@NeilRashbrook
Copy link
Copy Markdown
Contributor Author

It contains object of multiple subtypes, but you happen to know that the one you're trying to find has a specific subtype.

Comment thread lib/collection/array.d.ts Outdated
* order, until it finds one where `filterFunc` returns true. If such an element is found, find
* immediately returns that element valuehttps://github.com/microsoft/TypeScript/blob/main/src/lib/es2016.array.include.d.tsOtherwise, find returns undefined.
*/
find<T extends Item>(filterFunc: (item: Item) => item is T): T;
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks almost the same as the line below. Can we just keep your new one and delete the old one? (Would it break anything?)

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(both comments apply to all changes, not only this one)

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The first line is needed for when the function is being used to find an item of a specific subtype, and the second line is for all other cases.

Comment thread lib/collection/array.d.ts Outdated
* order, until it finds one where `filterFunc` returns true. If such an element is found, find
* immediately returns that element valuehttps://github.com/microsoft/TypeScript/blob/main/src/lib/es2016.array.include.d.tsOtherwise, find returns undefined.
*/
find<T extends Item>(filterFunc: (item: Item) => item is T): T;
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The filterFunc returns boolean, not an item. It merely says whether the item that was passed into filterFunc is the one that we wanted to find.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

item is T is a special TypeScript subtype of boolean which also asserts that the type of item is T when the value is true.

If you write

for (let value of array) {
  if (value instanceof Dervied) {
    value.doDerivedSpecificThing();
  }
}

Typescript recognises the instanceof check as changing the type of value to Derived. You could say that the expression value instanceof Derived has type value is Derived.

However when you're doing something slightly more complicated such as defining the return type of the find function you need to explicitly say that if the match function is of type item is T then the find function will always return an item of type T.

@benbucksch
Copy link
Copy Markdown
Owner

item is T is a special TypeScript subtype of boolean which also asserts that the type of item is T when the value is true.

Can you please add this as comment?

And please make your additional definition the second line. As-is, the primary definition (which should be first anyways) is losing the JSDoc definition.

@NeilRashbrook
Copy link
Copy Markdown
Contributor Author

And please make your additional definition the second line. As-is, the primary definition (which should be first anyways) is losing the JSDoc definition.

Sorry, but TypeScript requires that the most generic definition be last.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants