diff --git a/Jakefile.js b/Jakefile.js index 89fcb6500ddc6..a6f0bf54dc33a 100644 --- a/Jakefile.js +++ b/Jakefile.js @@ -128,6 +128,7 @@ var harnessSources = harnessCoreSources.concat([ "transpile.ts", "reuseProgramStructure.ts", "textStorage.ts", + "checkerPublicRelationships.ts", "moduleResolution.ts", "tsconfigParsing.ts", "builder.ts", diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 649deef7e3a92..78767c069542c 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -254,6 +254,50 @@ namespace ts { return resolveName(location, escapeLeadingUnderscores(name), meaning, /*nameNotFoundMessage*/ undefined, /*nameArg*/ undefined, /*isUse*/ false); }, getJsxNamespace: () => unescapeLeadingUnderscores(getJsxNamespace()), + + isIdenticalTo: (a, b) => checkTypeRelatedTo(a, b, identityRelation, /*errorNode*/ undefined), + isSubtypeOf: (a, b) => checkTypeRelatedTo(a, b, subtypeRelation, /*errorNode*/ undefined), + isAssignableTo: (a, b) => checkTypeRelatedTo(a, b, assignableRelation, /*errorNode*/ undefined), + isComparableTo: areTypesComparable, + isInstantiationOf: (a, b) => { + return a && b && (a.target === b); + }, + + lookupGlobalType: name => { + const symbol = getSymbol(globals, escapeLeadingUnderscores(name), SymbolFlags.Type); + return symbol ? getDeclaredTypeOfSymbol(symbol) : unknownType; + }, + lookupGlobalValueType: name => { + const symbol = getSymbol(globals, escapeLeadingUnderscores(name), SymbolFlags.Value); + return symbol ? getTypeOfSymbol(symbol) : unknownType; + }, + lookupTypeAt: (name, node) => { + const symbol = resolveName(node, escapeLeadingUnderscores(name), SymbolFlags.Type, /*nameNotFoundMessage*/undefined, /*nameArg*/undefined, /*isUse*/ false); + return symbol ? getDeclaredTypeOfSymbol(symbol) : unknownType; + }, + lookupValueTypeAt: (name, node) => { + const symbol = resolveName(node, escapeLeadingUnderscores(name), SymbolFlags.Value, /*nameNotFoundMessage*/undefined, /*nameArg*/undefined, /*isUse*/ false); + return symbol ? getTypeOfSymbol(symbol) : unknownType; + }, + getTypeOfSymbol, + getUnknownType: () => unknownType, + getStringLiteralType: (text: string) => { + /* tslint:disable:no-null-keyword */ + Debug.assert(text !== undefined && text !== null, "Argument to getStringLiteralType was null or undefined"); + /* tslint:enable:no-null-keyword */ + Debug.assert(typeof text === "string", "Argument to getStringLiteralType not a string"); + return getLiteralType(text); + }, + getNumberLiteralType: (num: number) => { + /* tslint:disable:no-null-keyword */ + Debug.assert(num !== undefined && num !== null, "Argument to getNumberLiteralType was null or undefined"); + /* tslint:enable:no-null-keyword */ + Debug.assert(typeof num === "number", "Argument to getStringLiteralType not a number"); + return getLiteralType(num); + }, + getFalseType: () => falseType, + getTrueType: () => trueType, + getNonPrimitiveType: () => nonPrimitiveType, }; const tupleTypes: GenericType[] = []; diff --git a/src/compiler/types.ts b/src/compiler/types.ts index adab1f32492ab..8173da48e77ed 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -2725,15 +2725,6 @@ namespace ts { getSuggestionForNonexistentSymbol(location: Node, name: string, meaning: SymbolFlags): string | undefined; /* @internal */ getBaseConstraintOfType(type: Type): Type | undefined; - /* @internal */ getAnyType(): Type; - /* @internal */ getStringType(): Type; - /* @internal */ getNumberType(): Type; - /* @internal */ getBooleanType(): Type; - /* @internal */ getVoidType(): Type; - /* @internal */ getUndefinedType(): Type; - /* @internal */ getNullType(): Type; - /* @internal */ getESSymbolType(): Type; - /* @internal */ getNeverType(): Type; /* @internal */ getUnionType(types: Type[], subtypeReduction?: boolean): Type; /* @internal */ createArrayType(elementType: Type): Type; /* @internal */ createPromiseType(type: Type): Type; @@ -2745,8 +2736,104 @@ namespace ts { /* @internal */ isSymbolAccessible(symbol: Symbol, enclosingDeclaration: Node, meaning: SymbolFlags, shouldComputeAliasToMarkVisible: boolean): SymbolAccessibilityResult; /* @internal */ tryFindAmbientModuleWithoutAugmentations(moduleName: string): Symbol | undefined; + /* @internal */ getSymbolWalker(accept?: (symbol: Symbol) => boolean): SymbolWalker; + /** + * Two types are considered identical when + * - they are both the `any` type, + * - they are the same primitive type, + * - they are the same type parameter, + * - they are union types with identical sets of constituent types, or + * - they are intersection types with identical sets of constituent types, or + * - they are object types with identical sets of members. + * + * This relationship is bidirectional. + * See [here](https://github.com/Microsoft/TypeScript/blob/master/doc/spec.md#3.11.2) for more information. + */ + isIdenticalTo(a: Type, b: Type): boolean; + /** + * `a` is a ___subtype___ of `b` (and `b` is a ___supertype___ of `a`) if `a` has no excess properties with respect to `b`, + * and one of the following is true: + * - `a` and `b` are identical types. + * - `b` is the `any` type. + * - `a` is the `undefined` type. + * - `a` is the `null` type and `b` is _not_ the `undefined` type. + * - `a` is an enum type and `b` is the primitive type `number`. + * - `a` is a string literal type and `b` is the primitive type `string`. + * - `a` is a union type and each constituient type of `b` is a subtype of `b`. + * - `a` is an intersection type and at least one constituent type of `a` is a subtype of `b`. + * - `b` is a union type and `a` is a subtype of at least one constituent type of `b`. + * - `b` is an intersection type and `a` is a subtype of each constituent type of `b`. + * - `a` is a type parameter and the constraint of `a` is a subtype of `b`. + * - `a` has a subset of the structural members of `b`. + * + * This relationship is directional. + * See [here](https://github.com/Microsoft/TypeScript/blob/master/doc/spec.md#3.11.3) for more information. + */ + isSubtypeOf(a: Type, b: Type): boolean; + /** + * The assignable relationship differs only from the subtype relationship in that: + * - the `any` type is assignable to, but not a subtype of, all types + * - the primitive type `number` is assignable to, but not a subtype of, all enum types, and + * - an object type without a particular property is assignable to an object type in which that property is optional. + * + * This relationship is directional. + * See [here](https://github.com/Microsoft/TypeScript/blob/master/doc/spec.md#3.11.4) for more information. + */ + isAssignableTo(a: Type, b: Type): boolean; + /** + * True if `a` is assignable to `b`, or `b` is assignable to `a`. Additionally, all unions with + * overlapping constituient types are comparable, and unit types in the same domain are comparable. + * This relationship is bidirectional. + */ + isComparableTo(a: Type, b: Type): boolean; + /** + * Not a formal relationship - returns true if a is an instantiation of the generic type b + */ + isInstantiationOf(a: GenericType, b: GenericType): boolean; + + /** + * Returns the declared type of the globally named symbol with meaning SymbolFlags.Type + * Returns the unknown type on failure. + */ + lookupGlobalType(name: string): Type; + /** + * Returns the declared type of the globally named symbol with meaning SymbolFlags.Value + * Returns the unknown type on failure. + */ + lookupGlobalValueType(name: string): Type; + /** + * Returns the declared type of the named symbol lexically at the position specified with meaning SymbolFlags.Type + * Returns the unknown type on failure. + */ + lookupTypeAt(name: string, position: Node): Type; + /** + * Returns the declared type of the named symbol lexically at the position specified with meaning SymbolFlags.Value + * Returns the unknown type on failure. + */ + lookupValueTypeAt(name: string, position: Node): Type; + /** + * Returns the type of a symbol + */ + getTypeOfSymbol(symbol: Symbol): Type; + + getAnyType(): Type; + getStringType(): Type; + getNumberType(): Type; + getBooleanType(): Type; + getVoidType(): Type; + getUndefinedType(): Type; + getNullType(): Type; + getESSymbolType(): Type; + getNeverType(): Type; + getUnknownType(): Type; + getStringLiteralType(text: string): LiteralType; + getNumberLiteralType(num: number): LiteralType; + getFalseType(): Type; + getTrueType(): Type; + getNonPrimitiveType(): Type; + // Should not be called directly. Should only be accessed through the Program instance. /* @internal */ getDiagnostics(sourceFile?: SourceFile, cancellationToken?: CancellationToken): Diagnostic[]; /* @internal */ getGlobalDiagnostics(): Diagnostic[]; diff --git a/src/harness/tsconfig.json b/src/harness/tsconfig.json index 6e61b7690bc79..5002509ad02bc 100644 --- a/src/harness/tsconfig.json +++ b/src/harness/tsconfig.json @@ -115,6 +115,7 @@ "./unittests/convertToBase64.ts", "./unittests/transpile.ts", "./unittests/reuseProgramStructure.ts", + "./unittests/checkerPublicRelationships.ts", "./unittests/moduleResolution.ts", "./unittests/tsconfigParsing.ts", "./unittests/builder.ts", diff --git a/src/harness/unittests/checkerPublicRelationships.ts b/src/harness/unittests/checkerPublicRelationships.ts new file mode 100644 index 0000000000000..9b901a8884b73 --- /dev/null +++ b/src/harness/unittests/checkerPublicRelationships.ts @@ -0,0 +1,195 @@ +/// +/// + +namespace ts { + describe("Type Checker Public Relationship APIs", () => { + let checker: TypeChecker; + let host: CompilerHost; + let program: Program; + before(() => { + host = Harness.Compiler.createCompilerHost([{ + unitName: "test.ts", + content: ` + type FunctionAlias = Function; + function foo() { + type Function = { myBrand: 42 } & FunctionAlias; + return (() => {}) as any as Function; + } + function foo2(x: T) { + type Function = { myBrand: T } & FunctionAlias; + const ret = (() => {}) as any as Function; + ret.myBrand = x; + return ret; + } + const xs: number[] = [1,2,3]; + ` + }], () => void 0, ScriptTarget.ES3, /*useCaseSensitiveFileNames*/ true, "", NewLineKind.CarriageReturnLineFeed); + program = ts.createProgram(["test.ts"], ts.defaultInitCompilerOptions, host); + const diag = ts.getPreEmitDiagnostics(program); + if (diag.length) { + const errors = ts.formatDiagnostics(diag, host); + console.log(errors); + } + checker = program.getTypeChecker(); + }); + + it("can get the any type", () => { + assert(checker.getAnyType().flags & TypeFlags.Any); + }); + + it("can get the string type", () => { + assert(checker.getStringType().flags & TypeFlags.String); + }); + + it("can get the number type", () => { + assert(checker.getNumberType().flags & TypeFlags.Number); + }); + + it("can get the boolean type", () => { + assert(checker.getBooleanType().flags & TypeFlags.Boolean); + }); + + it("can get the void type", () => { + assert(checker.getVoidType().flags & TypeFlags.Void); + }); + + it("can get the undefined type", () => { + assert(checker.getUndefinedType().flags & TypeFlags.Undefined); + }); + + it("can get the null type", () => { + assert(checker.getNullType().flags & TypeFlags.Null); + }); + + it("can get the essymbol type", () => { + assert(checker.getESSymbolType().flags & TypeFlags.ESSymbol); + }); + + it("can get the never type", () => { + assert(checker.getNeverType().flags & TypeFlags.Never); + }); + + it("can get the unknown type", () => { + assert(checker.getUnknownType().flags & TypeFlags.Any); + assert(checker.getUnknownType() === checker.getUnknownType()); + }); + + it("can get the true type", () => { + assert(checker.getTrueType().flags & TypeFlags.BooleanLiteral); + }); + + it("can get the false type", () => { + assert(checker.getFalseType().flags & TypeFlags.BooleanLiteral); + }); + + it("ensures true and false are different types", () => { + assert(checker.getFalseType() !== checker.getTrueType()); + }); + + it("can get the non-primitive type", () => { + assert(checker.getNonPrimitiveType().flags & TypeFlags.NonPrimitive); + }); + + it("can get string literal types", () => { + assert(checker.getStringLiteralType("foobar").value === "foobar"); + }); + + it("can get numeber literal types", () => { + assert(checker.getNumberLiteralType(42).value === 42); + }); + + it("doesn't choke on exceptional input to literal type getters", () => { + assert.equal(checker.getStringLiteralType("").value, ""); + assert.throws(() => checker.getStringLiteralType(/*content*/ undefined), Error, "Argument to getStringLiteralType was null or undefined"); + /* tslint:disable:no-null-keyword */ + assert.throws(() => checker.getNumberLiteralType(/*content*/ null), Error, "Argument to getNumberLiteralType was null or undefined"); + /* tslint:enable:no-null-keyword */ + let hugeStringLiteral = map(new Array(2 ** 16 - 1), () => "a").join(); + assert.equal(checker.getStringLiteralType(hugeStringLiteral).value, hugeStringLiteral); + hugeStringLiteral = undefined; + + const sanityChecks = ["000", "0b0", "0x0", "0.0", "0e-0", "-010", "-0b10", "-0x10", "-0o10", "-10.0", "-1e-1", "NaN", "Infinity", "-Infinity"]; + forEach(sanityChecks, num => { + assert.equal(checker.getStringLiteralType(num).value, num, `${num} did not match.`); + }); + + const insanityChecks = [0, 0b0, -10, Infinity, -Infinity]; + forEach(insanityChecks, (num) => { + assert.equal(checker.getNumberLiteralType(num).value, num, `${JSON.stringify(num)} should be ${num}`); + }); + + assert.isNaN(checker.getNumberLiteralType(NaN).value); + + const instabilityChecks = [{ foo: 42 }, new Date(42), [42], new Number(42), new String("42")]; + forEach(instabilityChecks, (bad) => { + assert.throws(() => checker.getStringLiteralType(bad as any)); + }); + }); + + it("can look up global types", () => { + assert.equal(checker.lookupGlobalType("Array").symbol.name, "Array", "Array global symbol not named Array"); + const globalFunction = checker.lookupGlobalType("Function"); + const globalAlias = checker.lookupGlobalType("FunctionAlias"); + assert.notEqual(globalFunction, checker.getUnknownType(), "The global function type should not be the unknown type"); + assert.notEqual(globalAlias, checker.getUnknownType(), "The global alias function type should not be the unknown type"); + const globalFunctionLength = globalFunction.getProperty("length"); + const aliasFunctionLength = globalAlias.getProperty("length"); + assert(globalFunctionLength, "Global function length symbol should exist"); + assert(aliasFunctionLength, "Alias function length symbol should exist"); + assert.notEqual(checker.getTypeOfSymbol(globalFunctionLength), checker.getUnknownType(), "The global function's length type should not be unknown"); + assert.notEqual(checker.getTypeOfSymbol(aliasFunctionLength), checker.getUnknownType(), "The alias function's length type should not be unknown"); + assert.equal(checker.getTypeOfSymbol(globalFunctionLength), checker.getTypeOfSymbol(aliasFunctionLength), "Alias and global function length were not identical types"); + assert.equal((checker.getTypeOfSymbol(globalFunctionLength) as IntrinsicType).intrinsicName, (checker.getNumberType() as IntrinsicType).intrinsicName, "Function length was not number type"); + }); + + it("can look up types in a given scope", () => { + assert(program.getSourceFile("test.ts"), "Test file not found"); + const functionBody = forEachChild(program.getSourceFile("test.ts"), node => node.kind === SyntaxKind.FunctionDeclaration ? (node as FunctionDeclaration) : undefined).body; + assert(functionBody, "Function body missing"); + const innerFunction = checker.lookupTypeAt("Function", functionBody.statements[functionBody.statements.length - 1]); + assert(innerFunction, "Inner function type missing"); + assert.notEqual(innerFunction, checker.getUnknownType(), "Inner function type should not be unknown"); + assert.notEqual(checker.lookupGlobalType("Function"), innerFunction, "Inner function type should be different than global"); + const brandNameType = checker.getTypeOfSymbol(innerFunction.getProperty("myBrand")); + assert.notEqual(brandNameType, checker.getUnknownType(), "Brand type on inner function should not be unknown"); + assert.equal(brandNameType, checker.getNumberLiteralType(42), "Brand type should be 42"); + + let skipped = false; + const functionBody2 = forEachChild(program.getSourceFile("test.ts"), node => node.kind === SyntaxKind.FunctionDeclaration ? skipped ? (node as FunctionDeclaration) : (skipped = true, undefined) : undefined).body; + assert(functionBody2, "Function body missing"); + const innerFunction2 = checker.lookupTypeAt("Function", functionBody2.statements[functionBody2.statements.length - 1]); + assert(innerFunction2, "Inner function type missing"); + assert.notEqual(innerFunction2, checker.getUnknownType(), "Inner function type should not be unknown"); + assert.notEqual(checker.lookupGlobalType("Function"), innerFunction2, "Inner function type should be different than global"); + const brandNameType2 = checker.getTypeOfSymbol(innerFunction2.getProperty("myBrand")); + assert.notEqual(brandNameType2, checker.getUnknownType(), "Brand type on inner function should not be unknown"); + const functionType = checker.lookupGlobalValueType("foo2"); + assert.notEqual(functionType, checker.getUnknownType(), "foo2 function type should not be unknown"); + assert(brandNameType2.flags & TypeFlags.TypeParameter, "Brand should be a type parameter"); + assert.equal(brandNameType2, checker.lookupGlobalValueType("foo2").getCallSignatures()[0].getTypeParameters()[0], "Brand type should be a type parameter"); + }); + + it("can compare types using all the builtin relationships", () => { + assert(checker.isSubtypeOf(checker.getNumberType(), checker.getAnyType()), "Any should be a subtype of number"); + assert.isFalse(checker.isSubtypeOf(checker.getAnyType(), checker.getNumberType()), "Number should not be a subtype of any"); + + assert(checker.isAssignableTo(checker.getAnyType(), checker.getNumberType()), "Any should be assignable to number"); + assert(checker.isAssignableTo(checker.getFalseType(), checker.getBooleanType()), "False should be assignable to boolean"); + + assert(checker.isComparableTo(checker.getBooleanType(), checker.getFalseType()), "False and boolean are comparable"); + assert(checker.isComparableTo(checker.getFalseType(), checker.getBooleanType()), "Boolean and false are comparable"); + + const variableType = checker.lookupGlobalValueType("xs"); + const globalArrayType = checker.lookupGlobalType("Array"); + assert.notEqual(variableType, checker.getUnknownType(), "xs type should not be unknown"); + assert.notEqual(globalArrayType, checker.getUnknownType(), "Global array type should not be unknown"); + assert(checker.isInstantiationOf(checker.lookupGlobalValueType("xs") as GenericType, checker.lookupGlobalType("Array") as GenericType)); + }); + + after(() => { + checker = undefined; + host = undefined; + program = undefined; + }); + }); +} \ No newline at end of file diff --git a/tests/baselines/reference/api/tsserverlibrary.d.ts b/tests/baselines/reference/api/tsserverlibrary.d.ts index 85895ffbce428..352d5b2b5bb42 100644 --- a/tests/baselines/reference/api/tsserverlibrary.d.ts +++ b/tests/baselines/reference/api/tsserverlibrary.d.ts @@ -1778,6 +1778,98 @@ declare namespace ts { getApparentType(type: Type): Type; getSuggestionForNonexistentProperty(node: Identifier, containingType: Type): string | undefined; getSuggestionForNonexistentSymbol(location: Node, name: string, meaning: SymbolFlags): string | undefined; + /** + * Two types are considered identical when + * - they are both the `any` type, + * - they are the same primitive type, + * - they are the same type parameter, + * - they are union types with identical sets of constituent types, or + * - they are intersection types with identical sets of constituent types, or + * - they are object types with identical sets of members. + * + * This relationship is bidirectional. + * See [here](https://github.com/Microsoft/TypeScript/blob/master/doc/spec.md#3.11.2) for more information. + */ + isIdenticalTo(a: Type, b: Type): boolean; + /** + * `a` is a ___subtype___ of `b` (and `b` is a ___supertype___ of `a`) if `a` has no excess properties with respect to `b`, + * and one of the following is true: + * - `a` and `b` are identical types. + * - `b` is the `any` type. + * - `a` is the `undefined` type. + * - `a` is the `null` type and `b` is _not_ the `undefined` type. + * - `a` is an enum type and `b` is the primitive type `number`. + * - `a` is a string literal type and `b` is the primitive type `string`. + * - `a` is a union type and each constituient type of `b` is a subtype of `b`. + * - `a` is an intersection type and at least one constituent type of `a` is a subtype of `b`. + * - `b` is a union type and `a` is a subtype of at least one constituent type of `b`. + * - `b` is an intersection type and `a` is a subtype of each constituent type of `b`. + * - `a` is a type parameter and the constraint of `a` is a subtype of `b`. + * - `a` has a subset of the structural members of `b`. + * + * This relationship is directional. + * See [here](https://github.com/Microsoft/TypeScript/blob/master/doc/spec.md#3.11.3) for more information. + */ + isSubtypeOf(a: Type, b: Type): boolean; + /** + * The assignable relationship differs only from the subtype relationship in that: + * - the `any` type is assignable to, but not a subtype of, all types + * - the primitive type `number` is assignable to, but not a subtype of, all enum types, and + * - an object type without a particular property is assignable to an object type in which that property is optional. + * + * This relationship is directional. + * See [here](https://github.com/Microsoft/TypeScript/blob/master/doc/spec.md#3.11.4) for more information. + */ + isAssignableTo(a: Type, b: Type): boolean; + /** + * True if `a` is assignable to `b`, or `b` is assignable to `a`. Additionally, all unions with + * overlapping constituient types are comparable, and unit types in the same domain are comparable. + * This relationship is bidirectional. + */ + isComparableTo(a: Type, b: Type): boolean; + /** + * Not a formal relationship - returns true if a is an instantiation of the generic type b + */ + isInstantiationOf(a: GenericType, b: GenericType): boolean; + /** + * Returns the declared type of the globally named symbol with meaning SymbolFlags.Type + * Returns the unknown type on failure. + */ + lookupGlobalType(name: string): Type; + /** + * Returns the declared type of the globally named symbol with meaning SymbolFlags.Value + * Returns the unknown type on failure. + */ + lookupGlobalValueType(name: string): Type; + /** + * Returns the declared type of the named symbol lexically at the position specified with meaning SymbolFlags.Type + * Returns the unknown type on failure. + */ + lookupTypeAt(name: string, position: Node): Type; + /** + * Returns the declared type of the named symbol lexically at the position specified with meaning SymbolFlags.Value + * Returns the unknown type on failure. + */ + lookupValueTypeAt(name: string, position: Node): Type; + /** + * Returns the type of a symbol + */ + getTypeOfSymbol(symbol: Symbol): Type; + getAnyType(): Type; + getStringType(): Type; + getNumberType(): Type; + getBooleanType(): Type; + getVoidType(): Type; + getUndefinedType(): Type; + getNullType(): Type; + getESSymbolType(): Type; + getNeverType(): Type; + getUnknownType(): Type; + getStringLiteralType(text: string): LiteralType; + getNumberLiteralType(num: number): LiteralType; + getFalseType(): Type; + getTrueType(): Type; + getNonPrimitiveType(): Type; } enum NodeBuilderFlags { None = 0, diff --git a/tests/baselines/reference/api/typescript.d.ts b/tests/baselines/reference/api/typescript.d.ts index fd58e72181ab1..790c4fa8e3df8 100644 --- a/tests/baselines/reference/api/typescript.d.ts +++ b/tests/baselines/reference/api/typescript.d.ts @@ -1778,6 +1778,98 @@ declare namespace ts { getApparentType(type: Type): Type; getSuggestionForNonexistentProperty(node: Identifier, containingType: Type): string | undefined; getSuggestionForNonexistentSymbol(location: Node, name: string, meaning: SymbolFlags): string | undefined; + /** + * Two types are considered identical when + * - they are both the `any` type, + * - they are the same primitive type, + * - they are the same type parameter, + * - they are union types with identical sets of constituent types, or + * - they are intersection types with identical sets of constituent types, or + * - they are object types with identical sets of members. + * + * This relationship is bidirectional. + * See [here](https://github.com/Microsoft/TypeScript/blob/master/doc/spec.md#3.11.2) for more information. + */ + isIdenticalTo(a: Type, b: Type): boolean; + /** + * `a` is a ___subtype___ of `b` (and `b` is a ___supertype___ of `a`) if `a` has no excess properties with respect to `b`, + * and one of the following is true: + * - `a` and `b` are identical types. + * - `b` is the `any` type. + * - `a` is the `undefined` type. + * - `a` is the `null` type and `b` is _not_ the `undefined` type. + * - `a` is an enum type and `b` is the primitive type `number`. + * - `a` is a string literal type and `b` is the primitive type `string`. + * - `a` is a union type and each constituient type of `b` is a subtype of `b`. + * - `a` is an intersection type and at least one constituent type of `a` is a subtype of `b`. + * - `b` is a union type and `a` is a subtype of at least one constituent type of `b`. + * - `b` is an intersection type and `a` is a subtype of each constituent type of `b`. + * - `a` is a type parameter and the constraint of `a` is a subtype of `b`. + * - `a` has a subset of the structural members of `b`. + * + * This relationship is directional. + * See [here](https://github.com/Microsoft/TypeScript/blob/master/doc/spec.md#3.11.3) for more information. + */ + isSubtypeOf(a: Type, b: Type): boolean; + /** + * The assignable relationship differs only from the subtype relationship in that: + * - the `any` type is assignable to, but not a subtype of, all types + * - the primitive type `number` is assignable to, but not a subtype of, all enum types, and + * - an object type without a particular property is assignable to an object type in which that property is optional. + * + * This relationship is directional. + * See [here](https://github.com/Microsoft/TypeScript/blob/master/doc/spec.md#3.11.4) for more information. + */ + isAssignableTo(a: Type, b: Type): boolean; + /** + * True if `a` is assignable to `b`, or `b` is assignable to `a`. Additionally, all unions with + * overlapping constituient types are comparable, and unit types in the same domain are comparable. + * This relationship is bidirectional. + */ + isComparableTo(a: Type, b: Type): boolean; + /** + * Not a formal relationship - returns true if a is an instantiation of the generic type b + */ + isInstantiationOf(a: GenericType, b: GenericType): boolean; + /** + * Returns the declared type of the globally named symbol with meaning SymbolFlags.Type + * Returns the unknown type on failure. + */ + lookupGlobalType(name: string): Type; + /** + * Returns the declared type of the globally named symbol with meaning SymbolFlags.Value + * Returns the unknown type on failure. + */ + lookupGlobalValueType(name: string): Type; + /** + * Returns the declared type of the named symbol lexically at the position specified with meaning SymbolFlags.Type + * Returns the unknown type on failure. + */ + lookupTypeAt(name: string, position: Node): Type; + /** + * Returns the declared type of the named symbol lexically at the position specified with meaning SymbolFlags.Value + * Returns the unknown type on failure. + */ + lookupValueTypeAt(name: string, position: Node): Type; + /** + * Returns the type of a symbol + */ + getTypeOfSymbol(symbol: Symbol): Type; + getAnyType(): Type; + getStringType(): Type; + getNumberType(): Type; + getBooleanType(): Type; + getVoidType(): Type; + getUndefinedType(): Type; + getNullType(): Type; + getESSymbolType(): Type; + getNeverType(): Type; + getUnknownType(): Type; + getStringLiteralType(text: string): LiteralType; + getNumberLiteralType(num: number): LiteralType; + getFalseType(): Type; + getTrueType(): Type; + getNonPrimitiveType(): Type; } enum NodeBuilderFlags { None = 0,