1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120
|
// @strict: true
interface A { a: string }
interface B extends A { b: string }
interface C extends A { c: string }
declare function cast<T, U extends T>(x: T, test: (x: T) => x is U): U;
declare function isC(x: A): x is C;
function f1(a: A, b: B) {
const x1 = cast(a, isC); // cast<A, C>
const x2 = cast(b, isC); // cast<A, C>
}
declare function useA(a: A): void;
declare function consume<T, U extends T>(t: T, u: U, f: (x: T) => void): void;
function f2(b: B, c: C) {
consume(b, c, useA); // consume<A, C>
consume(c, b, useA); // consume<A, B>
consume(b, b, useA); // consume<B, B>
consume(c, c, useA); // consume<C, C>
}
declare function every<T, U extends T>(array: readonly T[], f: (x: T) => x is U): array is readonly U[];
function f3(arr: readonly B[] | readonly C[]) {
if (every(arr, isC)) {
arr; // readonly C[]
}
else {
arr; // readonly B[]
}
}
// Repro from #52111
enum SyntaxKind {
Block,
Identifier,
CaseClause,
FunctionExpression,
FunctionDeclaration,
}
interface Node { kind: SyntaxKind; }
interface Expression extends Node { _expressionBrand: any; }
interface Declaration extends Node { _declarationBrand: any; }
interface Block extends Node { kind: SyntaxKind.Block; }
interface Identifier extends Expression, Declaration { kind: SyntaxKind.Identifier; }
interface CaseClause extends Node { kind: SyntaxKind.CaseClause; }
interface FunctionDeclaration extends Declaration { kind: SyntaxKind.FunctionDeclaration; }
type HasLocals = Block | FunctionDeclaration;
declare function canHaveLocals(node: Node): node is HasLocals;
declare function assertNode<T extends Node, U extends T>(node: T | undefined, test: (node: T) => node is U): asserts node is U;
declare function assertNode(node: Node | undefined, test: ((node: Node) => boolean) | undefined): void;
function foo(node: FunctionDeclaration | CaseClause) {
assertNode(node, canHaveLocals); // assertNode<Node, HasLocals>
node; // FunctionDeclaration
}
declare function isExpression(node: Node): node is Expression;
declare function tryCast<TOut extends TIn, TIn = any>(value: TIn | undefined, test: (value: TIn) => value is TOut): TOut;
function bar(node: Identifier | FunctionDeclaration) {
const a = tryCast(node, isExpression); // tryCast<Expression, Node>
}
// Repro from #49924
const enum SyntaxKind1 {
ClassExpression,
ClassStatement,
}
interface Node1 {
kind: SyntaxKind1;
}
interface Statement1 extends Node1 {
_statementBrand: any;
}
interface ClassExpression1 extends Node1 {
kind: SyntaxKind1.ClassExpression;
}
interface ClassStatement1 extends Statement1 {
kind: SyntaxKind1.ClassStatement;
}
type ClassLike1 = ClassExpression1 | ClassStatement1;
declare function isClassLike(node: Node1): node is ClassLike1;
declare const statement: Statement1 | undefined;
const maybeClassStatement = tryCast(statement, isClassLike); // ClassLike1
// Repro from #49924
interface TypeNode extends Node {
typeInfo: string;
}
interface NodeArray<T extends Node> extends Array<T> {
someProp: string;
}
declare function isNodeArray<T extends Node>(array: readonly T[]): array is NodeArray<T>;
declare const types: readonly TypeNode[];
const x = tryCast(types, isNodeArray); // NodeAray<TypeNode>
|