-
Notifications
You must be signed in to change notification settings - Fork 12.8k
Allow inline type predicates #6474
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
Comments
Here's a workaround that gets removed by bundlers const Narrow = <T>(v): v is T => true;
if (foo.nodeType === 1 && Narrow<Element>(foo)) {
} (edit 2022) Here's another workaround that works as a statement (= works in switch blocks) function Narrow<T extends R, R = unknown>(value: R): asserts value is T {}
switch (foo.nodeType) {
case 1: {
foo; // any
Narrow<Element>(foo);
foo; // Element
}
} |
Combined: function narrow <T>(value: unknown, expr: unknown): value is T {
return Boolean(expr);
}
declare const foo: Node;
if (narrow<Element>(foo, foo.nodeType === 1)) {
foo; // Element
} |
@saschanaz What would it look like using if (foo.nodeType === 1 as foo is Element) {
foo; // Element
} |
It should probably still be with parens - |
Here is another workaround:
|
+1 for proper compound predicates Aside: You can hack this now by packing the candidates into a tuple (and then unpacking): declare function isPair (tuple: readonly [Node, Node]): tuple is [Element, Text];
declare const foo: Node;
declare const bar: Node;
const fooBarPack = [foo, bar] as const;
if (isPair(fooBarPack)) {
const [
foo,
//^? const foo: Element
bar,
//^? const bar: Text
] = fooBarPack;
} Of course (because it's a hack) it requires (wastefully) creating that tuple. |
You could also imagine doing this as the annotation for a variable holding the predicate's result, i.e.: declare const foo: Node;
const isElement: foo is Element = foo.nodeType === 1;
if (isElement) {
// Assume foo is Element here
} |
The ideal API for this in my opinion would be something similar to the way that type guard functions assert types, but allowed in more places, like on if-statements. For example: Before — requires separate function for type guardingfunction isIterable<T>(obj: Iterable<T> | ArrayLike<T>): obj is Iterable<T> {
return typeof (obj as Iterable<T>)[Symbol.iterator] === 'function';
}
function iterateOver<T>(obj: Iterable<T> | ArrayLike<T>, expose: Function) {
if (isIterable(obj)) {
// some logic here
} else {
// some logic here
}
} After — can handle type guarding inline via if statementfunction iterateOver<T>(obj: Iterable<T> | ArrayLike<T>, expose: Function) {
const isIterable = typeof (obj as Iterable<T>)[Symbol.iterator] === 'function';
if (isIterable): obj is Iterable<T> {
// some logic here
} else {
// some logic here
}
} ** this could just as easily be rewritten to get rid of the function iterateOver<T>(obj: Iterable<T> | ArrayLike<T>, expose: Function) {
if (typeof (obj as Iterable<T>)[Symbol.iterator] === 'function'): obj is Iterable<T> {
// some logic here
} else {
// some logic here
}
} |
From #5731
A proposal from @sandersn: #5731 (comment)
The text was updated successfully, but these errors were encountered: