diff --git a/Jakefile.js b/Jakefile.js index d327b5bb47b..17346e8bc1f 100644 --- a/Jakefile.js +++ b/Jakefile.js @@ -250,6 +250,7 @@ var harnessSources = harnessCoreSources.concat([ "convertToBase64.ts", "transpile.ts", "reuseProgramStructure.ts", + "textStorage.ts", "cachingInServerLSHost.ts", "moduleResolution.ts", "tsconfigParsing.ts", diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 67c4db715e2..6bbbab8822e 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -3484,20 +3484,7 @@ namespace ts { } if (!popTypeResolution()) { - if ((symbol.valueDeclaration).type) { - // Variable has type annotation that circularly references the variable itself - type = unknownType; - error(symbol.valueDeclaration, Diagnostics._0_is_referenced_directly_or_indirectly_in_its_own_type_annotation, - symbolToString(symbol)); - } - else { - // Variable has initializer that circularly references the variable itself - type = anyType; - if (compilerOptions.noImplicitAny) { - error(symbol.valueDeclaration, Diagnostics._0_implicitly_has_type_any_because_it_does_not_have_a_type_annotation_and_is_referenced_directly_or_indirectly_in_its_own_initializer, - symbolToString(symbol)); - } - } + type = reportCircularityError(symbol); } links.type = type; } @@ -3631,11 +3618,33 @@ namespace ts { function getTypeOfInstantiatedSymbol(symbol: Symbol): Type { const links = getSymbolLinks(symbol); if (!links.type) { - links.type = instantiateType(getTypeOfSymbol(links.target), links.mapper); + if (!pushTypeResolution(symbol, TypeSystemPropertyName.Type)) { + return unknownType; + } + let type = instantiateType(getTypeOfSymbol(links.target), links.mapper); + if (!popTypeResolution()) { + type = reportCircularityError(symbol); + } + links.type = type; } return links.type; } + function reportCircularityError(symbol: Symbol) { + // Check if variable has type annotation that circularly references the variable itself + if ((symbol.valueDeclaration).type) { + error(symbol.valueDeclaration, Diagnostics._0_is_referenced_directly_or_indirectly_in_its_own_type_annotation, + symbolToString(symbol)); + return unknownType; + } + // Otherwise variable has initializer that circularly references the variable itself + if (compilerOptions.noImplicitAny) { + error(symbol.valueDeclaration, Diagnostics._0_implicitly_has_type_any_because_it_does_not_have_a_type_annotation_and_is_referenced_directly_or_indirectly_in_its_own_initializer, + symbolToString(symbol)); + } + return anyType; + } + function getTypeOfSymbol(symbol: Symbol): Type { if (symbol.flags & SymbolFlags.Instantiated) { return getTypeOfInstantiatedSymbol(symbol); @@ -4524,12 +4533,11 @@ namespace ts { // Resolve upfront such that recursive references see an empty object type. setStructuredTypeMembers(type, emptySymbols, emptyArray, emptyArray, undefined, undefined); // In { [P in K]: T }, we refer to P as the type parameter type, K as the constraint type, - // and T as the template type. If K is of the form 'keyof S', the mapped type and S are - // homomorphic and we copy property modifiers from corresponding properties in S. + // and T as the template type. const typeParameter = getTypeParameterFromMappedType(type); const constraintType = getConstraintTypeFromMappedType(type); - const homomorphicType = getHomomorphicTypeFromMappedType(type); const templateType = getTemplateTypeFromMappedType(type); + const modifiersType = getModifiersTypeFromMappedType(type); const templateReadonly = !!type.declaration.readonlyToken; const templateOptional = !!type.declaration.questionToken; // First, if the constraint type is a type parameter, obtain the base constraint. Then, @@ -4548,11 +4556,11 @@ namespace ts { // Otherwise, for type string create a string index signature. if (t.flags & TypeFlags.StringLiteral) { const propName = (t).text; - const homomorphicProp = homomorphicType && getPropertyOfType(homomorphicType, propName); - const isOptional = templateOptional || !!(homomorphicProp && homomorphicProp.flags & SymbolFlags.Optional); + const modifiersProp = getPropertyOfType(modifiersType, propName); + const isOptional = templateOptional || !!(modifiersProp && modifiersProp.flags & SymbolFlags.Optional); const prop = createSymbol(SymbolFlags.Property | SymbolFlags.Transient | (isOptional ? SymbolFlags.Optional : 0), propName); prop.type = propType; - prop.isReadonly = templateReadonly || homomorphicProp && isReadonlySymbol(homomorphicProp); + prop.isReadonly = templateReadonly || modifiersProp && isReadonlySymbol(modifiersProp); members.set(propName, prop); } else if (t.flags & TypeFlags.String) { @@ -4579,9 +4587,16 @@ namespace ts { unknownType); } - function getHomomorphicTypeFromMappedType(type: MappedType) { - const constraint = getConstraintDeclaration(getTypeParameterFromMappedType(type)); - return constraint.kind === SyntaxKind.TypeOperator ? instantiateType(getTypeFromTypeNode((constraint).type), type.mapper || identityMapper) : undefined; + function getModifiersTypeFromMappedType(type: MappedType) { + if (!type.modifiersType) { + // If the mapped type was declared as { [P in keyof T]: X } or as { [P in K]: X }, where + // K is constrained to 'K extends keyof T', then we will copy property modifiers from T. + const declaredType = getTypeFromMappedTypeNode(type.declaration); + const constraint = getConstraintTypeFromMappedType(declaredType); + const extendedConstraint = constraint.flags & TypeFlags.TypeParameter ? getConstraintOfTypeParameter(constraint) : constraint; + type.modifiersType = extendedConstraint.flags & TypeFlags.Index ? instantiateType((extendedConstraint).type, type.mapper || identityMapper) : emptyObjectType; + } + return type.modifiersType; } function getErasedTemplateTypeFromMappedType(type: MappedType) { @@ -4678,33 +4693,24 @@ namespace ts { * The apparent type of a type parameter is the base constraint instantiated with the type parameter * as the type argument for the 'this' type. */ - function getApparentTypeOfTypeParameter(type: TypeParameter) { + function getApparentTypeOfTypeVariable(type: TypeVariable) { if (!type.resolvedApparentType) { - let constraintType = getConstraintOfTypeParameter(type); + let constraintType = getConstraintOfTypeVariable(type); while (constraintType && constraintType.flags & TypeFlags.TypeParameter) { - constraintType = getConstraintOfTypeParameter(constraintType); + constraintType = getConstraintOfTypeVariable(constraintType); } type.resolvedApparentType = getTypeWithThisArgument(constraintType || emptyObjectType, type); } return type.resolvedApparentType; } - /** - * The apparent type of an indexed access T[K] is the type of T's string index signature, if any. - */ - function getApparentTypeOfIndexedAccess(type: IndexedAccessType) { - return getIndexTypeOfType(getApparentType(type.objectType), IndexKind.String) || type; - } - /** * For a type parameter, return the base constraint of the type parameter. For the string, number, * boolean, and symbol primitive types, return the corresponding object types. Otherwise return the * type itself. Note that the apparent type of a union type is the union type itself. */ function getApparentType(type: Type): Type { - const t = type.flags & TypeFlags.TypeParameter ? getApparentTypeOfTypeParameter(type) : - type.flags & TypeFlags.IndexedAccess ? getApparentTypeOfIndexedAccess(type) : - type; + const t = type.flags & TypeFlags.TypeVariable ? getApparentTypeOfTypeVariable(type) : type; return t.flags & TypeFlags.StringLike ? globalStringType : t.flags & TypeFlags.NumberLike ? globalNumberType : t.flags & TypeFlags.BooleanLike ? globalBooleanType : @@ -5290,6 +5296,12 @@ namespace ts { return typeParameter.constraint === noConstraintType ? undefined : typeParameter.constraint; } + function getConstraintOfTypeVariable(type: TypeVariable): Type { + return type.flags & TypeFlags.TypeParameter ? getConstraintOfTypeParameter(type) : + type.flags & TypeFlags.IndexedAccess ? (type).constraint : + undefined; + } + function getParentSymbolOfTypeParameter(typeParameter: TypeParameter): Symbol { return getSymbolOfNode(getDeclarationOfKind(typeParameter.symbol, SyntaxKind.TypeParameter).parent); } @@ -5965,6 +5977,24 @@ namespace ts { const type = createType(TypeFlags.IndexedAccess); type.objectType = objectType; type.indexType = indexType; + // We eagerly compute the constraint of the indexed access type such that circularity + // errors are immediately caught and reported. For example, class C { x: this["x"] } + // becomes an error only when the constraint is eagerly computed. + if (type.objectType.flags & TypeFlags.StructuredType) { + // The constraint of T[K], where T is an object, union, or intersection type, + // is the type of the string index signature of T, if any. + type.constraint = getIndexTypeOfType(type.objectType, IndexKind.String); + } + else if (type.objectType.flags & TypeFlags.TypeVariable) { + // The constraint of T[K], where T is a type variable, is A[K], where A is the + // apparent type of T. + const apparentType = getApparentTypeOfTypeVariable(type.objectType); + if (apparentType !== emptyObjectType) { + type.constraint = isTypeOfKind((type).indexType, TypeFlags.StringLike) ? + getIndexedAccessType(apparentType, (type).indexType) : + getIndexTypeOfType(apparentType, IndexKind.String); + } + } return type; } @@ -6043,14 +6073,19 @@ namespace ts { } function getIndexedAccessType(objectType: Type, indexType: Type, accessNode?: ElementAccessExpression | IndexedAccessTypeNode) { - if (maybeTypeOfKind(indexType, TypeFlags.TypeVariable | TypeFlags.Index) || isGenericMappedType(objectType)) { + // If the index type is generic, if the object type is generic and doesn't originate in an expression, + // or if the object type is a mapped type with a generic constraint, we are performing a higher-order + // index access where we cannot meaningfully access the properties of the object type. Note that for a + // generic T and a non-generic K, we eagerly resolve T[K] if it originates in an expression. This is to + // preserve backwards compatibility. For example, an element access 'this["foo"]' has always been resolved + // eagerly using the constraint type of 'this' at the given location. + if (maybeTypeOfKind(indexType, TypeFlags.TypeVariable | TypeFlags.Index) || + maybeTypeOfKind(objectType, TypeFlags.TypeVariable) && !(accessNode && accessNode.kind === SyntaxKind.ElementAccessExpression) || + isGenericMappedType(objectType)) { if (objectType.flags & TypeFlags.Any) { return objectType; } - // If the index type is generic or if the object type is a mapped type with a generic constraint, - // we are performing a higher-order index access where we cannot meaningfully access the properties - // of the object type. In those cases, we first check that the index type is assignable to 'keyof T' - // for the object type. + // We first check that the index type is assignable to 'keyof T' for the object type. if (accessNode) { if (!isTypeAssignableTo(indexType, getIndexType(objectType))) { error(accessNode, Diagnostics.Type_0_cannot_be_used_to_index_type_1, typeToString(indexType), typeToString(objectType)); @@ -6067,6 +6102,7 @@ namespace ts { const id = objectType.id + "," + indexType.id; return indexedAccessTypes.get(id) || set(indexedAccessTypes, id, createIndexedAccessType(objectType, indexType)); } + // In the following we resolve T[K] to the type of the property in T selected by K. const apparentObjectType = getApparentType(objectType); if (indexType.flags & TypeFlags.Union && !(indexType.flags & TypeFlags.Primitive)) { const propTypes: Type[] = []; @@ -7255,8 +7291,7 @@ namespace ts { return result; } } - - if (target.flags & TypeFlags.TypeParameter) { + else if (target.flags & TypeFlags.TypeParameter) { // A source type { [P in keyof T]: X } is related to a target type T if X is related to T[P]. if (getObjectFlags(source) & ObjectFlags.Mapped && getConstraintTypeFromMappedType(source) === getIndexType(target)) { if (!(source).declaration.questionToken) { @@ -7285,10 +7320,10 @@ namespace ts { return result; } } - // Given a type parameter T with a constraint C, a type S is assignable to + // Given a type variable T with a constraint C, a type S is assignable to // keyof T if S is assignable to keyof C. - if ((target).type.flags & TypeFlags.TypeParameter) { - const constraint = getConstraintOfTypeParameter((target).type); + if ((target).type.flags & TypeFlags.TypeVariable) { + const constraint = getConstraintOfTypeVariable((target).type); if (constraint) { if (result = isRelatedTo(source, getIndexType(constraint), reportErrors)) { return result; @@ -7304,6 +7339,14 @@ namespace ts { return result; } } + // A type S is related to a type T[K] if S is related to A[K], where K is string-like and + // A is the apparent type of S. + if ((target).constraint) { + if (result = isRelatedTo(source, (target).constraint, reportErrors)) { + errorInfo = saveErrorInfo; + return result; + } + } } if (source.flags & TypeFlags.TypeParameter) { @@ -7312,6 +7355,7 @@ namespace ts { const indexedAccessType = getIndexedAccessType(source, getTypeParameterFromMappedType(target)); const templateType = getTemplateTypeFromMappedType(target); if (result = isRelatedTo(indexedAccessType, templateType, reportErrors)) { + errorInfo = saveErrorInfo; return result; } } @@ -7333,6 +7377,16 @@ namespace ts { } } } + else if (source.flags & TypeFlags.IndexedAccess) { + // A type S[K] is related to a type T if A[K] is related to T, where K is string-like and + // A is the apparent type of S. + if ((source).constraint) { + if (result = isRelatedTo((source).constraint, target, reportErrors)) { + errorInfo = saveErrorInfo; + return result; + } + } + } else { if (getObjectFlags(source) & ObjectFlags.Reference && getObjectFlags(target) & ObjectFlags.Reference && (source).target === (target).target) { // We have type references to same target type, see if relationship holds for all type arguments @@ -13488,13 +13542,14 @@ namespace ts { const containingClass = getContainingClass(node); if (containingClass) { const containingType = getTypeOfNode(containingClass); - const baseTypes = getBaseTypes(containingType); - if (baseTypes.length) { + let baseTypes = getBaseTypes(containingType as InterfaceType); + while (baseTypes.length) { const baseType = baseTypes[0]; if (modifiers & ModifierFlags.Protected && baseType.symbol === declaration.parent.symbol) { return true; } + baseTypes = getBaseTypes(baseType as InterfaceType); } } if (modifiers & ModifierFlags.Private) { @@ -15002,8 +15057,8 @@ namespace ts { function isLiteralContextualType(contextualType: Type) { if (contextualType) { - if (contextualType.flags & TypeFlags.TypeParameter) { - const apparentType = getApparentTypeOfTypeParameter(contextualType); + if (contextualType.flags & TypeFlags.TypeVariable) { + const apparentType = getApparentTypeOfTypeVariable(contextualType); // If the type parameter is constrained to the base primitive type we're checking for, // consider this a literal context. For example, given a type parameter 'T extends string', // this causes us to infer string literal types for T. @@ -15838,7 +15893,7 @@ namespace ts { checkSourceElement(node.type); const type = getTypeFromMappedTypeNode(node); const constraintType = getConstraintTypeFromMappedType(type); - const keyType = constraintType.flags & TypeFlags.TypeParameter ? getApparentTypeOfTypeParameter(constraintType) : constraintType; + const keyType = constraintType.flags & TypeFlags.TypeVariable ? getApparentTypeOfTypeVariable(constraintType) : constraintType; checkTypeAssignableTo(keyType, stringType, node.typeParameter.constraint); } @@ -16713,6 +16768,14 @@ namespace ts { } } + function isRemovedPropertyFromObjectSpread(node: Node) { + if (isBindingElement(node) && isObjectBindingPattern(node.parent)) { + const lastElement = lastOrUndefined(node.parent.elements); + return lastElement !== node && !!lastElement.dotDotDotToken; + } + return false; + } + function errorUnusedLocal(node: Node, name: string) { if (isIdentifierThatStartsWithUnderScore(node)) { const declaration = getRootDeclaration(node.parent); @@ -16722,7 +16785,10 @@ namespace ts { return; } } - error(node, Diagnostics._0_is_declared_but_never_used, name); + + if (!isRemovedPropertyFromObjectSpread(node.kind === SyntaxKind.Identifier ? node.parent : node)) { + error(node, Diagnostics._0_is_declared_but_never_used, name); + } } function parameterNameStartsWithUnderscore(parameterName: DeclarationName) { diff --git a/src/compiler/commandLineParser.ts b/src/compiler/commandLineParser.ts index 7571804b5f4..b3c538afd0a 100644 --- a/src/compiler/commandLineParser.ts +++ b/src/compiler/commandLineParser.ts @@ -840,7 +840,7 @@ namespace ts { * @param basePath A root directory to resolve relative path entries in the config * file to. e.g. outDir */ - export function parseJsonConfigFileContent(json: any, host: ParseConfigHost, basePath: string, existingOptions: CompilerOptions = {}, configFileName?: string, resolutionStack: Path[] = []): ParsedCommandLine { + export function parseJsonConfigFileContent(json: any, host: ParseConfigHost, basePath: string, existingOptions: CompilerOptions = {}, configFileName?: string, resolutionStack: Path[] = [], extraFileExtensions: FileExtensionInfo[] = []): ParsedCommandLine { const errors: Diagnostic[] = []; const getCanonicalFileName = createGetCanonicalFileName(host.useCaseSensitiveFileNames); const resolvedPath = toPath(configFileName || "", basePath, getCanonicalFileName); @@ -980,7 +980,7 @@ namespace ts { includeSpecs = ["**/*"]; } - const result = matchFileNames(fileNames, includeSpecs, excludeSpecs, basePath, options, host, errors); + const result = matchFileNames(fileNames, includeSpecs, excludeSpecs, basePath, options, host, errors, extraFileExtensions); if (result.fileNames.length === 0 && !hasProperty(json, "files") && resolutionStack.length === 0) { errors.push( @@ -1185,7 +1185,7 @@ namespace ts { * @param host The host used to resolve files and directories. * @param errors An array for diagnostic reporting. */ - function matchFileNames(fileNames: string[], include: string[], exclude: string[], basePath: string, options: CompilerOptions, host: ParseConfigHost, errors: Diagnostic[]): ExpandResult { + function matchFileNames(fileNames: string[], include: string[], exclude: string[], basePath: string, options: CompilerOptions, host: ParseConfigHost, errors: Diagnostic[], extraFileExtensions: FileExtensionInfo[]): ExpandResult { basePath = normalizePath(basePath); // The exclude spec list is converted into a regular expression, which allows us to quickly @@ -1219,7 +1219,7 @@ namespace ts { // Rather than requery this for each file and filespec, we query the supported extensions // once and store it on the expansion context. - const supportedExtensions = getSupportedExtensions(options); + const supportedExtensions = getSupportedExtensions(options, extraFileExtensions); // Literal files are always included verbatim. An "include" or "exclude" specification cannot // remove a literal file. diff --git a/src/compiler/core.ts b/src/compiler/core.ts index 3c370f7b154..fd9eedeeece 100644 --- a/src/compiler/core.ts +++ b/src/compiler/core.ts @@ -2032,8 +2032,18 @@ namespace ts { export const supportedJavascriptExtensions = [".js", ".jsx"]; const allSupportedExtensions = supportedTypeScriptExtensions.concat(supportedJavascriptExtensions); - export function getSupportedExtensions(options?: CompilerOptions): string[] { - return options && options.allowJs ? allSupportedExtensions : supportedTypeScriptExtensions; + export function getSupportedExtensions(options?: CompilerOptions, extraFileExtensions?: FileExtensionInfo[]): string[] { + const needAllExtensions = options && options.allowJs; + if (!extraFileExtensions || extraFileExtensions.length === 0) { + return needAllExtensions ? allSupportedExtensions : supportedTypeScriptExtensions; + } + const extensions = (needAllExtensions ? allSupportedExtensions : supportedTypeScriptExtensions).slice(0); + for (const extInfo of extraFileExtensions) { + if (needAllExtensions || extInfo.scriptKind === ScriptKind.TS) { + extensions.push(extInfo.extension); + } + } + return extensions; } export function hasJavaScriptFileExtension(fileName: string) { @@ -2044,10 +2054,10 @@ namespace ts { return forEach(supportedTypeScriptExtensions, extension => fileExtensionIs(fileName, extension)); } - export function isSupportedSourceFileName(fileName: string, compilerOptions?: CompilerOptions) { + export function isSupportedSourceFileName(fileName: string, compilerOptions?: CompilerOptions, extraFileExtensions?: FileExtensionInfo[]) { if (!fileName) { return false; } - for (const extension of getSupportedExtensions(compilerOptions)) { + for (const extension of getSupportedExtensions(compilerOptions, extraFileExtensions)) { if (fileExtensionIs(fileName, extension)) { return true; } diff --git a/src/compiler/types.ts b/src/compiler/types.ts index ca2295e5ba2..b98a5a493ba 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -2948,6 +2948,7 @@ namespace ts { typeParameter?: TypeParameter; constraintType?: Type; templateType?: Type; + modifiersType?: Type; mapper?: TypeMapper; // Instantiation mapper } @@ -2983,6 +2984,8 @@ namespace ts { } export interface TypeVariable extends Type { + /* @internal */ + resolvedApparentType: Type; /* @internal */ resolvedIndexType: IndexType; } @@ -2995,8 +2998,6 @@ namespace ts { /* @internal */ mapper?: TypeMapper; // Instantiation mapper /* @internal */ - resolvedApparentType: Type; - /* @internal */ isThisType?: boolean; } @@ -3005,6 +3006,7 @@ namespace ts { export interface IndexedAccessType extends TypeVariable { objectType: Type; indexType: Type; + constraint?: Type; } // keyof T types (TypeFlags.Index) @@ -3101,6 +3103,12 @@ namespace ts { ThisProperty } + export interface FileExtensionInfo { + extension: string; + scriptKind: ScriptKind; + isMixedContent: boolean; + } + export interface DiagnosticMessage { key: string; category: DiagnosticCategory; diff --git a/src/harness/unittests/textStorage.ts b/src/harness/unittests/textStorage.ts new file mode 100644 index 00000000000..b4287f2610c --- /dev/null +++ b/src/harness/unittests/textStorage.ts @@ -0,0 +1,70 @@ +/// +/// +/// + +namespace ts.textStorage { + describe("Text storage", () => { + const f = { + path: "/a/app.ts", + content: ` + let x = 1; + let y = 2; + function bar(a: number) { + return a + 1; + }` + }; + + it("text based storage should be have exactly the same as script version cache", () => { + + const host = ts.projectSystem.createServerHost([f]); + + const ts1 = new server.TextStorage(host, server.asNormalizedPath(f.path)); + const ts2 = new server.TextStorage(host, server.asNormalizedPath(f.path)); + + ts1.useScriptVersionCache(); + ts2.useText(); + + const lineMap = computeLineStarts(f.content); + + for (let line = 0; line < lineMap.length; line++) { + const start = lineMap[line]; + const end = line === lineMap.length - 1 ? f.path.length : lineMap[line + 1]; + + for (let offset = 0; offset < end - start; offset++) { + const pos1 = ts1.lineOffsetToPosition(line + 1, offset + 1); + const pos2 = ts2.lineOffsetToPosition(line + 1, offset + 1); + assert.isTrue(pos1 === pos2, `lineOffsetToPosition ${line + 1}-${offset + 1}: expected ${pos1} to equal ${pos2}`); + } + + const {start: start1, length: length1 } = ts1.lineToTextSpan(line); + const {start: start2, length: length2 } = ts2.lineToTextSpan(line); + assert.isTrue(start1 === start2, `lineToTextSpan ${line}::start:: expected ${start1} to equal ${start2}`); + assert.isTrue(length1 === length2, `lineToTextSpan ${line}::length:: expected ${length1} to equal ${length2}`); + } + + for (let pos = 0; pos < f.content.length; pos++) { + const { line: line1, offset: offset1 } = ts1.positionToLineOffset(pos); + const { line: line2, offset: offset2 } = ts2.positionToLineOffset(pos); + assert.isTrue(line1 === line2, `positionToLineOffset ${pos}::line:: expected ${line1} to equal ${line2}`); + assert.isTrue(offset1 === offset2, `positionToLineOffset ${pos}::offset:: expected ${offset1} to equal ${offset2}`); + } + }); + + it("should switch to script version cache if necessary", () => { + const host = ts.projectSystem.createServerHost([f]); + const ts1 = new server.TextStorage(host, server.asNormalizedPath(f.path)); + + ts1.getSnapshot(); + assert.isTrue(!ts1.hasScriptVersionCache(), "should not have script version cache - 1"); + + ts1.edit(0, 5, " "); + assert.isTrue(ts1.hasScriptVersionCache(), "have script version cache - 1"); + + ts1.useText(); + assert.isTrue(!ts1.hasScriptVersionCache(), "should not have script version cache - 2"); + + ts1.getLineInfo(0); + assert.isTrue(ts1.hasScriptVersionCache(), "have script version cache - 2"); + }) + }); +} \ No newline at end of file diff --git a/src/harness/unittests/tsserverProjectSystem.ts b/src/harness/unittests/tsserverProjectSystem.ts index 9beefe480df..5b4ba7d7223 100644 --- a/src/harness/unittests/tsserverProjectSystem.ts +++ b/src/harness/unittests/tsserverProjectSystem.ts @@ -140,7 +140,6 @@ namespace ts.projectSystem { export interface TestServerHostCreationParameters { useCaseSensitiveFileNames?: boolean; executingFilePath?: string; - libFile?: FileOrFolder; currentDirectory?: string; } @@ -1137,6 +1136,69 @@ namespace ts.projectSystem { checkNumberOfProjects(projectService, {}); }); + it("reload regular file after closing", () => { + const f1 = { + path: "/a/b/app.ts", + content: "x." + }; + const f2 = { + path: "/a/b/lib.ts", + content: "let x: number;" + }; + + const host = createServerHost([f1, f2, libFile]); + const service = createProjectService(host); + service.openExternalProject({ projectFileName: "/a/b/project", rootFiles: toExternalFiles([f1.path, f2.path]), options: {} }) + + service.openClientFile(f1.path); + service.openClientFile(f2.path, "let x: string"); + + service.checkNumberOfProjects({ externalProjects: 1 }); + checkProjectActualFiles(service.externalProjects[0], [f1.path, f2.path, libFile.path]); + + const completions1 = service.externalProjects[0].getLanguageService().getCompletionsAtPosition(f1.path, 2); + // should contain completions for string + assert.isTrue(completions1.entries.some(e => e.name === "charAt"), "should contain 'charAt'"); + assert.isFalse(completions1.entries.some(e => e.name === "toExponential"), "should not contain 'toExponential'"); + + service.closeClientFile(f2.path); + const completions2 = service.externalProjects[0].getLanguageService().getCompletionsAtPosition(f1.path, 2); + // should contain completions for string + assert.isFalse(completions2.entries.some(e => e.name === "charAt"), "should not contain 'charAt'"); + assert.isTrue(completions2.entries.some(e => e.name === "toExponential"), "should contain 'toExponential'"); + }); + + it("clear mixed content file after closing", () => { + const f1 = { + path: "/a/b/app.ts", + content: " " + }; + const f2 = { + path: "/a/b/lib.html", + content: "" + }; + + const host = createServerHost([f1, f2, libFile]); + const service = createProjectService(host); + service.openExternalProject({ projectFileName: "/a/b/project", rootFiles: [{ fileName: f1.path }, { fileName: f2.path, hasMixedContent: true }], options: {} }) + + service.openClientFile(f1.path); + service.openClientFile(f2.path, "let somelongname: string"); + + service.checkNumberOfProjects({ externalProjects: 1 }); + checkProjectActualFiles(service.externalProjects[0], [f1.path, f2.path, libFile.path]); + + const completions1 = service.externalProjects[0].getLanguageService().getCompletionsAtPosition(f1.path, 0); + assert.isTrue(completions1.entries.some(e => e.name === "somelongname"), "should contain 'somelongname'"); + + service.closeClientFile(f2.path); + const completions2 = service.externalProjects[0].getLanguageService().getCompletionsAtPosition(f1.path, 0); + assert.isFalse(completions2.entries.some(e => e.name === "somelongname"), "should not contain 'somelongname'"); + const sf2 = service.externalProjects[0].getLanguageService().getProgram().getSourceFile(f2.path); + assert.equal(sf2.text, ""); + }); + + it("external project with included config file opened after configured project", () => { const file1 = { path: "/a/b/f1.ts", @@ -1521,6 +1583,67 @@ namespace ts.projectSystem { checkProjectActualFiles(projectService.inferredProjects[1], [file2.path]); }); + it("tsconfig script block support", () => { + const file1 = { + path: "/a/b/f1.ts", + content: ` ` + }; + const file2 = { + path: "/a/b/f2.html", + content: `var hello = "hello";` + }; + const config = { + path: "/a/b/tsconfig.json", + content: JSON.stringify({ compilerOptions: { allowJs: true } }) + }; + const host = createServerHost([file1, file2, config]); + const session = createSession(host); + openFilesForSession([file1], session); + const projectService = session.getProjectService(); + + // HTML file will not be included in any projects yet + checkNumberOfProjects(projectService, { configuredProjects: 1 }); + checkProjectActualFiles(projectService.configuredProjects[0], [file1.path]); + + // Specify .html extension as mixed content + const extraFileExtensions = [{ extension: ".html", scriptKind: ScriptKind.JS, isMixedContent: true }]; + const configureHostRequest = makeSessionRequest(CommandNames.Configure, { extraFileExtensions }); + session.executeCommand(configureHostRequest).response; + + // HTML file still not included in the project as it is closed + checkNumberOfProjects(projectService, { configuredProjects: 1 }); + checkProjectActualFiles(projectService.configuredProjects[0], [file1.path]); + + // Open HTML file + projectService.applyChangesInOpenFiles( + /*openFiles*/[{ fileName: file2.path, hasMixedContent: true, scriptKind: ScriptKind.JS, content: `var hello = "hello";` }], + /*changedFiles*/undefined, + /*closedFiles*/undefined); + + // Now HTML file is included in the project + checkNumberOfProjects(projectService, { configuredProjects: 1 }); + checkProjectActualFiles(projectService.configuredProjects[0], [file1.path, file2.path]); + + // Check identifiers defined in HTML content are available in .ts file + const project = projectService.configuredProjects[0]; + let completions = project.getLanguageService().getCompletionsAtPosition(file1.path, 1); + assert(completions && completions.entries[0].name === "hello", `expected entry hello to be in completion list`); + + // Close HTML file + projectService.applyChangesInOpenFiles( + /*openFiles*/undefined, + /*changedFiles*/undefined, + /*closedFiles*/[file2.path]); + + // HTML file is still included in project + checkNumberOfProjects(projectService, { configuredProjects: 1 }); + checkProjectActualFiles(projectService.configuredProjects[0], [file1.path, file2.path]); + + // Check identifiers defined in HTML content are not available in .ts file + completions = project.getLanguageService().getCompletionsAtPosition(file1.path, 5); + assert(completions && completions.entries[0].name !== "hello", `unexpected hello entry in completion list`); + }); + it("project structure update is deferred if files are not added\removed", () => { const file1 = { path: "/a/b/f1.ts", @@ -1566,7 +1689,7 @@ namespace ts.projectSystem { const project = projectService.externalProjects[0]; const scriptInfo = project.getScriptInfo(file1.path); - const snap = scriptInfo.snap(); + const snap = scriptInfo.getSnapshot(); const actualText = snap.getText(0, snap.getLength()); assert.equal(actualText, "", `expected content to be empty string, got "${actualText}"`); @@ -1579,7 +1702,7 @@ namespace ts.projectSystem { projectService.closeClientFile(file1.path); const scriptInfo2 = project.getScriptInfo(file1.path); - const snap2 = scriptInfo2.snap(); + const snap2 = scriptInfo2.getSnapshot(); const actualText2 = snap2.getText(0, snap.getLength()); assert.equal(actualText2, "", `expected content to be empty string, got "${actualText2}"`); }); @@ -2277,13 +2400,13 @@ namespace ts.projectSystem { p.updateGraph(); const scriptInfo = p.getScriptInfo(f.path); - checkSnapLength(scriptInfo.snap(), f.content.length); + checkSnapLength(scriptInfo.getSnapshot(), f.content.length); // open project and replace its content with empty string projectService.openClientFile(f.path, ""); - checkSnapLength(scriptInfo.snap(), 0); + checkSnapLength(scriptInfo.getSnapshot(), 0); }); - function checkSnapLength(snap: server.LineIndexSnapshot, expectedLength: number) { + function checkSnapLength(snap: IScriptSnapshot, expectedLength: number) { assert.equal(snap.getLength(), expectedLength, "Incorrect snapshot size"); } }); @@ -2436,7 +2559,6 @@ namespace ts.projectSystem { const cwd = { path: "/a/c" }; - debugger; const host = createServerHost([f1, config, node, cwd], { currentDirectory: cwd.path }); const projectService = createProjectService(host); projectService.openClientFile(f1.path); @@ -2707,7 +2829,7 @@ namespace ts.projectSystem { // verify content const projectServiice = session.getProjectService(); - const snap1 = projectServiice.getScriptInfo(f1.path).snap(); + const snap1 = projectServiice.getScriptInfo(f1.path).getSnapshot(); assert.equal(snap1.getText(0, snap1.getLength()), tmp.content, "content should be equal to the content of temp file"); // reload from original file file @@ -2719,7 +2841,7 @@ namespace ts.projectSystem { }); // verify content - const snap2 = projectServiice.getScriptInfo(f1.path).snap(); + const snap2 = projectServiice.getScriptInfo(f1.path).getSnapshot(); assert.equal(snap2.getText(0, snap2.getLength()), f1.content, "content should be equal to the content of original file"); }); diff --git a/src/server/editorServices.ts b/src/server/editorServices.ts index a358b0dab00..f558288f655 100644 --- a/src/server/editorServices.ts +++ b/src/server/editorServices.ts @@ -107,6 +107,7 @@ namespace ts.server { export interface HostConfiguration { formatCodeOptions: FormatCodeSettings; hostInfo: string; + extraFileExtensions?: FileExtensionInfo[]; } interface ConfigFileConversionResult { @@ -131,13 +132,16 @@ namespace ts.server { interface FilePropertyReader { getFileName(f: T): string; getScriptKind(f: T): ScriptKind; - hasMixedContent(f: T): boolean; + hasMixedContent(f: T, extraFileExtensions: FileExtensionInfo[]): boolean; } const fileNamePropertyReader: FilePropertyReader = { getFileName: x => x, getScriptKind: _ => undefined, - hasMixedContent: _ => false + hasMixedContent: (fileName, extraFileExtensions) => { + const mixedContentExtensions = ts.map(ts.filter(extraFileExtensions, item => item.isMixedContent), item => item.extension); + return forEach(mixedContentExtensions, extension => fileExtensionIs(fileName, extension)) + } }; const externalFilePropertyReader: FilePropertyReader = { @@ -282,7 +286,8 @@ namespace ts.server { this.hostConfiguration = { formatCodeOptions: getDefaultFormatCodeSettings(this.host), - hostInfo: "Unknown host" + hostInfo: "Unknown host", + extraFileExtensions: [] }; this.documentRegistry = createDocumentRegistry(host.useCaseSensitiveFileNames, host.getCurrentDirectory()); @@ -424,7 +429,7 @@ namespace ts.server { this.handleDeletedFile(info); } else { - if (info && (!info.isOpen)) { + if (info && (!info.isScriptOpen())) { // file has been changed which might affect the set of referenced files in projects that include // this file and set of inferred projects info.reloadFromFile(); @@ -440,7 +445,7 @@ namespace ts.server { // TODO: handle isOpen = true case - if (!info.isOpen) { + if (!info.isScriptOpen()) { this.filenameToScriptInfo.remove(info.path); this.lastDeletedFile = info; @@ -486,7 +491,7 @@ namespace ts.server { // If a change was made inside "folder/file", node will trigger the callback twice: // one with the fileName being "folder/file", and the other one with "folder". // We don't respond to the second one. - if (fileName && !ts.isSupportedSourceFileName(fileName, project.getCompilerOptions())) { + if (fileName && !ts.isSupportedSourceFileName(fileName, project.getCompilerOptions(), this.hostConfiguration.extraFileExtensions)) { return; } @@ -634,15 +639,17 @@ namespace ts.server { // Closing file should trigger re-reading the file content from disk. This is // because the user may chose to discard the buffer content before saving // to the disk, and the server's version of the file can be out of sync. - info.reloadFromFile(); + info.close(); removeItemFromSet(this.openFiles, info); - info.isOpen = false; // collect all projects that should be removed let projectsToRemove: Project[]; for (const p of info.containingProjects) { if (p.projectKind === ProjectKind.Configured) { + if (info.hasMixedContent) { + info.registerFileUpdate(); + } // last open file in configured project - close it if ((p).deleteOpenRef() === 0) { (projectsToRemove || (projectsToRemove = [])).push(p); @@ -811,7 +818,9 @@ namespace ts.server { this.host, getDirectoryPath(configFilename), /*existingOptions*/ {}, - configFilename); + configFilename, + /*resolutionStack*/ [], + this.hostConfiguration.extraFileExtensions); if (parsedCommandLine.errors.length) { errors = concatenate(errors, parsedCommandLine.errors); @@ -915,7 +924,7 @@ namespace ts.server { for (const f of files) { const rootFilename = propertyReader.getFileName(f); const scriptKind = propertyReader.getScriptKind(f); - const hasMixedContent = propertyReader.hasMixedContent(f); + const hasMixedContent = propertyReader.hasMixedContent(f, this.hostConfiguration.extraFileExtensions); if (this.host.fileExists(rootFilename)) { const info = this.getOrCreateScriptInfoForNormalizedPath(toNormalizedPath(rootFilename), /*openedByClient*/ clientFileName == rootFilename, /*fileContent*/ undefined, scriptKind, hasMixedContent); project.addRoot(info); @@ -961,7 +970,7 @@ namespace ts.server { rootFilesChanged = true; if (!scriptInfo) { const scriptKind = propertyReader.getScriptKind(f); - const hasMixedContent = propertyReader.hasMixedContent(f); + const hasMixedContent = propertyReader.hasMixedContent(f, this.hostConfiguration.extraFileExtensions); scriptInfo = this.getOrCreateScriptInfoForNormalizedPath(normalizedPath, /*openedByClient*/ false, /*fileContent*/ undefined, scriptKind, hasMixedContent); } } @@ -989,7 +998,7 @@ namespace ts.server { } if (toAdd) { for (const f of toAdd) { - if (f.isOpen && isRootFileInInferredProject(f)) { + if (f.isScriptOpen() && isRootFileInInferredProject(f)) { // if file is already root in some inferred project // - remove the file from that project and delete the project if necessary const inferredProject = f.containingProjects[0]; @@ -1089,32 +1098,34 @@ namespace ts.server { getOrCreateScriptInfoForNormalizedPath(fileName: NormalizedPath, openedByClient: boolean, fileContent?: string, scriptKind?: ScriptKind, hasMixedContent?: boolean) { let info = this.getScriptInfoForNormalizedPath(fileName); if (!info) { - let content: string; - if (this.host.fileExists(fileName)) { - // by default pick whatever content was supplied as the argument - // if argument was not given - then for mixed content files assume that its content is empty string - content = fileContent || (hasMixedContent ? "" : this.host.readFile(fileName)); - } - if (!content) { - if (openedByClient) { - content = ""; - } - } - if (content !== undefined) { - info = new ScriptInfo(this.host, fileName, content, scriptKind, openedByClient, hasMixedContent); - // do not watch files with mixed content - server doesn't know how to interpret it + if (openedByClient || this.host.fileExists(fileName)) { + info = new ScriptInfo(this.host, fileName, scriptKind, hasMixedContent); + this.filenameToScriptInfo.set(info.path, info); - if (!info.isOpen && !hasMixedContent) { - info.setWatcher(this.host.watchFile(fileName, _ => this.onSourceFileChanged(fileName))); + + if (openedByClient) { + if (fileContent === undefined) { + // if file is opened by client and its content is not specified - use file text + fileContent = this.host.readFile(fileName) || ""; + } + } + else { + // do not watch files with mixed content - server doesn't know how to interpret it + if (!hasMixedContent) { + info.setWatcher(this.host.watchFile(fileName, _ => this.onSourceFileChanged(fileName))); + } } } } if (info) { - if (fileContent !== undefined) { - info.reload(fileContent); + if (openedByClient && !info.isScriptOpen()) { + info.open(fileContent); + if (hasMixedContent) { + info.registerFileUpdate(); + } } - if (openedByClient) { - info.isOpen = true; + else if (fileContent !== undefined) { + info.reload(fileContent); } } return info; @@ -1146,6 +1157,10 @@ namespace ts.server { mergeMapLikes(this.hostConfiguration.formatCodeOptions, convertFormatOptions(args.formatOptions)); this.logger.info("Format host information updated"); } + if (args.extraFileExtensions) { + this.hostConfiguration.extraFileExtensions = args.extraFileExtensions; + this.logger.info("Host file extension mappings updated"); + } } } @@ -1230,7 +1245,6 @@ namespace ts.server { const info = this.getScriptInfoForNormalizedPath(toNormalizedPath(uncheckedFileName)); if (info) { this.closeOpenFile(info); - info.isOpen = false; } this.printProjects(); } @@ -1255,7 +1269,7 @@ namespace ts.server { if (openFiles) { for (const file of openFiles) { const scriptInfo = this.getScriptInfo(file.fileName); - Debug.assert(!scriptInfo || !scriptInfo.isOpen); + Debug.assert(!scriptInfo || !scriptInfo.isScriptOpen()); const normalizedPath = scriptInfo ? scriptInfo.fileName : toNormalizedPath(file.fileName); this.openClientFileWithNormalizedPath(normalizedPath, file.content, tryConvertScriptKindName(file.scriptKind), file.hasMixedContent); } diff --git a/src/server/lsHost.ts b/src/server/lsHost.ts index ffeeb57a0e8..1989b34c477 100644 --- a/src/server/lsHost.ts +++ b/src/server/lsHost.ts @@ -170,7 +170,7 @@ namespace ts.server { getScriptSnapshot(filename: string): ts.IScriptSnapshot { const scriptInfo = this.project.getScriptInfoLSHost(filename); if (scriptInfo) { - return scriptInfo.snap(); + return scriptInfo.getSnapshot(); } } diff --git a/src/server/project.ts b/src/server/project.ts index 14889dccd8a..4ff09003edc 100644 --- a/src/server/project.ts +++ b/src/server/project.ts @@ -1,4 +1,4 @@ -/// +/// /// /// /// @@ -187,6 +187,10 @@ namespace ts.server { public languageServiceEnabled = true; builder: Builder; + /** + * Set of files names that were updated since the last call to getChangesSinceVersion. + */ + private updatedFileNames: Map; /** * Set of files that was returned from the last call to getChangesSinceVersion. */ @@ -448,7 +452,7 @@ namespace ts.server { containsFile(filename: NormalizedPath, requireOpen?: boolean) { const info = this.projectService.getScriptInfoForNormalizedPath(filename); - if (info && (info.isOpen || !requireOpen)) { + if (info && (info.isScriptOpen() || !requireOpen)) { return this.containsScriptInfo(info); } } @@ -480,6 +484,10 @@ namespace ts.server { this.markAsDirty(); } + registerFileUpdate(fileName: string) { + (this.updatedFileNames || (this.updatedFileNames = createMap())).set(fileName, fileName); + } + markAsDirty() { this.projectStateVersion++; } @@ -667,10 +675,12 @@ namespace ts.server { isInferred: this.projectKind === ProjectKind.Inferred, options: this.getCompilerOptions() }; + const updatedFileNames = this.updatedFileNames; + this.updatedFileNames = undefined; // check if requested version is the same that we have reported last time if (this.lastReportedFileNames && lastKnownVersion === this.lastReportedVersion) { - // if current structure version is the same - return info witout any changes - if (this.projectStructureVersion == this.lastReportedVersion) { + // if current structure version is the same - return info without any changes + if (this.projectStructureVersion == this.lastReportedVersion && !updatedFileNames) { return { info, projectErrors: this.projectErrors }; } // compute and return the difference @@ -679,6 +689,8 @@ namespace ts.server { const added: string[] = []; const removed: string[] = []; + const updated: string[] = keysOfMap(updatedFileNames); + forEachKeyInMap(currentFiles, id => { if (!lastReportedFileNames.has(id)) { added.push(id); @@ -691,7 +703,7 @@ namespace ts.server { }); this.lastReportedFileNames = currentFiles; this.lastReportedVersion = this.projectStructureVersion; - return { info, changes: { added, removed }, projectErrors: this.projectErrors }; + return { info, changes: { added, removed, updated }, projectErrors: this.projectErrors }; } else { // unknown version - return everything diff --git a/src/server/protocol.ts b/src/server/protocol.ts index 1e29b029104..27faf417282 100644 --- a/src/server/protocol.ts +++ b/src/server/protocol.ts @@ -1,4 +1,4 @@ -/** +/** * Declaration module describing the TypeScript Server protocol */ namespace ts.server.protocol { @@ -918,6 +918,10 @@ namespace ts.server.protocol { * List of removed files */ removed: string[]; + /** + * List of updated files + */ + updated: string[]; } /** @@ -990,6 +994,11 @@ namespace ts.server.protocol { * The format options to use during formatting and other code editing features. */ formatOptions?: FormatCodeSettings; + + /** + * The host's additional supported file extensions + */ + extraFileExtensions?: FileExtensionInfo[]; } /** diff --git a/src/server/scriptInfo.ts b/src/server/scriptInfo.ts index fa9eac0e8e3..340510f6580 100644 --- a/src/server/scriptInfo.ts +++ b/src/server/scriptInfo.ts @@ -2,6 +2,161 @@ namespace ts.server { + /* @internal */ + export class TextStorage { + private svc: ScriptVersionCache | undefined; + private svcVersion = 0; + + private text: string; + private lineMap: number[]; + private textVersion = 0; + + constructor(private readonly host: ServerHost, private readonly fileName: NormalizedPath) { + } + + public getVersion() { + return this.svc + ? `SVC-${this.svcVersion}-${this.svc.getSnapshot().version}` + : `Text-${this.textVersion}`; + } + + public hasScriptVersionCache() { + return this.svc !== undefined; + } + + public useScriptVersionCache(newText?: string) { + this.switchToScriptVersionCache(newText); + } + + public useText(newText?: string) { + this.svc = undefined; + this.setText(newText); + } + + public edit(start: number, end: number, newText: string) { + this.switchToScriptVersionCache().edit(start, end - start, newText); + } + + public reload(text: string) { + if (this.svc) { + this.svc.reload(text); + } + else { + this.setText(text); + } + } + + public reloadFromFile(tempFileName?: string) { + if (this.svc || (tempFileName !== this.fileName)) { + this.reload(this.getFileText(tempFileName)) + } + else { + this.setText(undefined); + } + } + + public getSnapshot(): IScriptSnapshot { + return this.svc + ? this.svc.getSnapshot() + : ScriptSnapshot.fromString(this.getOrLoadText()); + } + + public getLineInfo(line: number) { + return this.switchToScriptVersionCache().getSnapshot().index.lineNumberToInfo(line); + } + /** + * @param line 0 based index + */ + lineToTextSpan(line: number) { + if (!this.svc) { + const lineMap = this.getLineMap(); + const start = lineMap[line]; // -1 since line is 1-based + const end = line + 1 < lineMap.length ? lineMap[line + 1] : this.text.length; + return ts.createTextSpanFromBounds(start, end); + } + const index = this.svc.getSnapshot().index; + const lineInfo = index.lineNumberToInfo(line + 1); + let len: number; + if (lineInfo.leaf) { + len = lineInfo.leaf.text.length; + } + else { + const nextLineInfo = index.lineNumberToInfo(line + 2); + len = nextLineInfo.offset - lineInfo.offset; + } + return ts.createTextSpan(lineInfo.offset, len); + } + + /** + * @param line 1 based index + * @param offset 1 based index + */ + lineOffsetToPosition(line: number, offset: number): number { + if (!this.svc) { + return computePositionOfLineAndCharacter(this.getLineMap(), line - 1, offset - 1); + } + const index = this.svc.getSnapshot().index; + + const lineInfo = index.lineNumberToInfo(line); + // TODO: assert this offset is actually on the line + return (lineInfo.offset + offset - 1); + } + + /** + * @param line 1-based index + * @param offset 1-based index + */ + positionToLineOffset(position: number): ILineInfo { + if (!this.svc) { + const { line, character } = computeLineAndCharacterOfPosition(this.getLineMap(), position); + return { line: line + 1, offset: character + 1 }; + } + const index = this.svc.getSnapshot().index; + const lineOffset = index.charOffsetToLineNumberAndPos(position); + return { line: lineOffset.line, offset: lineOffset.offset + 1 }; + } + + private getFileText(tempFileName?: string) { + return this.host.readFile(tempFileName || this.fileName) || ""; + } + + private ensureNoScriptVersionCache() { + Debug.assert(!this.svc, "ScriptVersionCache should not be set"); + } + + private switchToScriptVersionCache(newText?: string): ScriptVersionCache { + if (!this.svc) { + this.svc = ScriptVersionCache.fromString(this.host, newText !== undefined ? newText : this.getOrLoadText()); + this.svcVersion++; + this.text = undefined; + } + return this.svc; + } + + private getOrLoadText() { + this.ensureNoScriptVersionCache(); + if (this.text === undefined) { + this.setText(this.getFileText()); + } + return this.text; + } + + private getLineMap() { + this.ensureNoScriptVersionCache(); + return this.lineMap || (this.lineMap = computeLineStarts(this.getOrLoadText())); + } + + private setText(newText: string) { + this.ensureNoScriptVersionCache(); + if (newText === undefined || this.text !== newText) { + this.text = newText; + this.lineMap = undefined; + this.textVersion++; + } + } + } + + export class ScriptInfo { /** * All projects that include this file @@ -11,24 +166,46 @@ namespace ts.server { readonly path: Path; private fileWatcher: FileWatcher; - private svc: ScriptVersionCache; + private textStorage: TextStorage; + + private isOpen: boolean; - // TODO: allow to update hasMixedContent from the outside constructor( private readonly host: ServerHost, readonly fileName: NormalizedPath, - content: string, readonly scriptKind: ScriptKind, - public isOpen = false, public hasMixedContent = false) { this.path = toPath(fileName, host.getCurrentDirectory(), createGetCanonicalFileName(host.useCaseSensitiveFileNames)); - this.svc = ScriptVersionCache.fromString(host, content); + this.textStorage = new TextStorage(host, fileName); + if (hasMixedContent) { + this.textStorage.reload(""); + } this.scriptKind = scriptKind ? scriptKind : getScriptKindFromFileName(fileName); } + public isScriptOpen() { + return this.isOpen; + } + + public open(newText: string) { + this.isOpen = true; + this.textStorage.useScriptVersionCache(newText); + this.markContainingProjectsAsDirty(); + } + + public close() { + this.isOpen = false; + this.textStorage.useText(this.hasMixedContent ? "" : undefined); + this.markContainingProjectsAsDirty(); + } + + public getSnapshot() { + return this.textStorage.getSnapshot(); + } + getFormatCodeSettings() { return this.formatCodeSettings; } @@ -90,6 +267,12 @@ namespace ts.server { return this.containingProjects[0]; } + registerFileUpdate(): void { + for (const p of this.containingProjects) { + p.registerFileUpdate(this.path); + } + } + setFormatOptions(formatSettings: FormatCodeSettings): void { if (formatSettings) { if (!this.formatCodeSettings) { @@ -112,16 +295,16 @@ namespace ts.server { } getLatestVersion() { - return this.svc.latestVersion().toString(); + return this.textStorage.getVersion(); } reload(script: string) { - this.svc.reload(script); + this.textStorage.reload(script); this.markContainingProjectsAsDirty(); } saveTo(fileName: string) { - const snap = this.snap(); + const snap = this.textStorage.getSnapshot(); this.host.writeFile(fileName, snap.getText(0, snap.getLength())); } @@ -130,22 +313,17 @@ namespace ts.server { this.reload(""); } else { - this.svc.reloadFromFile(tempFileName || this.fileName); + this.textStorage.reloadFromFile(tempFileName); this.markContainingProjectsAsDirty(); } } - snap() { - return this.svc.getSnapshot(); - } - getLineInfo(line: number) { - const snap = this.snap(); - return snap.index.lineNumberToInfo(line); + return this.textStorage.getLineInfo(line); } editContent(start: number, end: number, newText: string): void { - this.svc.edit(start, end - start, newText); + this.textStorage.edit(start, end, newText); this.markContainingProjectsAsDirty(); } @@ -159,17 +337,7 @@ namespace ts.server { * @param line 1 based index */ lineToTextSpan(line: number) { - const index = this.snap().index; - const lineInfo = index.lineNumberToInfo(line + 1); - let len: number; - if (lineInfo.leaf) { - len = lineInfo.leaf.text.length; - } - else { - const nextLineInfo = index.lineNumberToInfo(line + 2); - len = nextLineInfo.offset - lineInfo.offset; - } - return ts.createTextSpan(lineInfo.offset, len); + return this.textStorage.lineToTextSpan(line); } /** @@ -177,11 +345,7 @@ namespace ts.server { * @param offset 1 based index */ lineOffsetToPosition(line: number, offset: number): number { - const index = this.snap().index; - - const lineInfo = index.lineNumberToInfo(line); - // TODO: assert this offset is actually on the line - return (lineInfo.offset + offset - 1); + return this.textStorage.lineOffsetToPosition(line, offset); } /** @@ -189,9 +353,7 @@ namespace ts.server { * @param offset 1-based index */ positionToLineOffset(position: number): ILineInfo { - const index = this.snap().index; - const lineOffset = index.charOffsetToLineNumberAndPos(position); - return { line: lineOffset.line, offset: lineOffset.offset + 1 }; + return this.textStorage.positionToLineOffset(position); } } } \ No newline at end of file diff --git a/src/server/scriptVersionCache.ts b/src/server/scriptVersionCache.ts index f094a183610..aaf04d39a1f 100644 --- a/src/server/scriptVersionCache.ts +++ b/src/server/scriptVersionCache.ts @@ -438,8 +438,9 @@ namespace ts.server { } } getChangeRange(oldSnapshot: ts.IScriptSnapshot): ts.TextChangeRange { - const oldSnap = oldSnapshot; - return this.getTextChangeRangeSinceVersion(oldSnap.version); + if (oldSnapshot instanceof LineIndexSnapshot) { + return this.getTextChangeRangeSinceVersion(oldSnapshot.version); + } } } diff --git a/src/server/session.ts b/src/server/session.ts index 0c200b33b84..203a940e7cf 100644 --- a/src/server/session.ts +++ b/src/server/session.ts @@ -709,7 +709,7 @@ namespace ts.server { const displayString = ts.displayPartsToString(nameInfo.displayParts); const nameSpan = nameInfo.textSpan; const nameColStart = scriptInfo.positionToLineOffset(nameSpan.start).offset; - const nameText = scriptInfo.snap().getText(nameSpan.start, ts.textSpanEnd(nameSpan)); + const nameText = scriptInfo.getSnapshot().getText(nameSpan.start, ts.textSpanEnd(nameSpan)); const refs = combineProjectOutput( projects, (project: Project) => { @@ -722,7 +722,7 @@ namespace ts.server { const refScriptInfo = project.getScriptInfo(ref.fileName); const start = refScriptInfo.positionToLineOffset(ref.textSpan.start); const refLineSpan = refScriptInfo.lineToTextSpan(start.line - 1); - const lineText = refScriptInfo.snap().getText(refLineSpan.start, ts.textSpanEnd(refLineSpan)).replace(/\r|\n/g, ""); + const lineText = refScriptInfo.getSnapshot().getText(refLineSpan.start, ts.textSpanEnd(refLineSpan)).replace(/\r|\n/g, ""); return { file: ref.fileName, start: start, @@ -1326,7 +1326,7 @@ namespace ts.server { highPriorityFiles.push(fileNameInProject); else { const info = this.projectService.getScriptInfo(fileNameInProject); - if (!info.isOpen) { + if (!info.isScriptOpen()) { if (fileNameInProject.indexOf(".d.ts") > 0) veryLowPriorityFiles.push(fileNameInProject); else diff --git a/src/server/utilities.ts b/src/server/utilities.ts index eb7801e5fd9..4b1149d31d4 100644 --- a/src/server/utilities.ts +++ b/src/server/utilities.ts @@ -1,4 +1,4 @@ -/// +/// /// namespace ts.server { diff --git a/src/services/jsDoc.ts b/src/services/jsDoc.ts index 3369ac23223..a937294567b 100644 --- a/src/services/jsDoc.ts +++ b/src/services/jsDoc.ts @@ -1,4 +1,4 @@ -/* @internal */ +/* @internal */ namespace ts.JsDoc { const jsDocTagNames = [ "augments", @@ -166,6 +166,7 @@ namespace ts.JsDoc { const lineStart = sourceFile.getLineStarts()[posLineAndChar.line]; const indentationStr = sourceFile.text.substr(lineStart, posLineAndChar.character); + const isJavaScriptFile = hasJavaScriptFileExtension(sourceFile.fileName); let docParams = ""; for (let i = 0, numParams = parameters.length; i < numParams; i++) { @@ -173,8 +174,12 @@ namespace ts.JsDoc { const paramName = currentName.kind === SyntaxKind.Identifier ? (currentName).text : "param" + i; - - docParams += `${indentationStr} * @param ${paramName}${newLine}`; + if (isJavaScriptFile) { + docParams += `${indentationStr} * @param {any} ${paramName}${newLine}`; + } + else { + docParams += `${indentationStr} * @param ${paramName}${newLine}`; + } } // A doc comment consists of the following diff --git a/src/services/services.ts b/src/services/services.ts index 77a5e916067..87ae9fb8561 100644 --- a/src/services/services.ts +++ b/src/services/services.ts @@ -1725,7 +1725,7 @@ namespace ts { const sourceFile = syntaxTreeCache.getCurrentSourceFile(fileName); // Check if in a context where we don't want to perform any insertion - if (isInString(sourceFile, position) || isInComment(sourceFile, position)) { + if (isInString(sourceFile, position)) { return false; } diff --git a/src/services/types.ts b/src/services/types.ts index 6a0e6e886b5..3865fe7fac9 100644 --- a/src/services/types.ts +++ b/src/services/types.ts @@ -91,7 +91,9 @@ namespace ts { } public getText(start: number, end: number): string { - return this.text.substring(start, end); + return start === 0 && end === this.text.length + ? this.text + : this.text.substring(start, end); } public getLength(): number { diff --git a/tests/baselines/reference/circularIndexedAccessErrors.errors.txt b/tests/baselines/reference/circularIndexedAccessErrors.errors.txt new file mode 100644 index 00000000000..e3076e08b7e --- /dev/null +++ b/tests/baselines/reference/circularIndexedAccessErrors.errors.txt @@ -0,0 +1,57 @@ +tests/cases/conformance/types/keyof/circularIndexedAccessErrors.ts(3,5): error TS2502: 'x' is referenced directly or indirectly in its own type annotation. +tests/cases/conformance/types/keyof/circularIndexedAccessErrors.ts(7,5): error TS2502: 'x' is referenced directly or indirectly in its own type annotation. +tests/cases/conformance/types/keyof/circularIndexedAccessErrors.ts(15,5): error TS2502: 'x' is referenced directly or indirectly in its own type annotation. +tests/cases/conformance/types/keyof/circularIndexedAccessErrors.ts(19,5): error TS2502: 'x' is referenced directly or indirectly in its own type annotation. +tests/cases/conformance/types/keyof/circularIndexedAccessErrors.ts(23,5): error TS2502: 'x' is referenced directly or indirectly in its own type annotation. +tests/cases/conformance/types/keyof/circularIndexedAccessErrors.ts(27,5): error TS2502: 'x' is referenced directly or indirectly in its own type annotation. +tests/cases/conformance/types/keyof/circularIndexedAccessErrors.ts(28,5): error TS2502: 'y' is referenced directly or indirectly in its own type annotation. +tests/cases/conformance/types/keyof/circularIndexedAccessErrors.ts(29,5): error TS2502: 'z' is referenced directly or indirectly in its own type annotation. + + +==== tests/cases/conformance/types/keyof/circularIndexedAccessErrors.ts (8 errors) ==== + + type T1 = { + x: T1["x"]; // Error + ~~~~~~~~~~~ +!!! error TS2502: 'x' is referenced directly or indirectly in its own type annotation. + }; + + type T2 = { + x: T2[K]; // Error + ~~~~~~~~~~~~ +!!! error TS2502: 'x' is referenced directly or indirectly in its own type annotation. + y: number; + } + + declare let x2: T2<"x">; + let x2x = x2.x; + + interface T3> { + x: T["x"]; // Error + ~~~~~~~~~~ +!!! error TS2502: 'x' is referenced directly or indirectly in its own type annotation. + } + + interface T4> { + x: T4["x"]; // Error + ~~~~~~~~~~~~~~ +!!! error TS2502: 'x' is referenced directly or indirectly in its own type annotation. + } + + class C1 { + x: C1["x"]; // Error + ~~~~~~~~~~~ +!!! error TS2502: 'x' is referenced directly or indirectly in its own type annotation. + } + + class C2 { + x: this["y"]; // Error + ~~~~~~~~~~~~~ +!!! error TS2502: 'x' is referenced directly or indirectly in its own type annotation. + y: this["z"]; // Error + ~~~~~~~~~~~~~ +!!! error TS2502: 'y' is referenced directly or indirectly in its own type annotation. + z: this["x"]; // Error + ~~~~~~~~~~~~~ +!!! error TS2502: 'z' is referenced directly or indirectly in its own type annotation. + } \ No newline at end of file diff --git a/tests/baselines/reference/circularIndexedAccessErrors.js b/tests/baselines/reference/circularIndexedAccessErrors.js new file mode 100644 index 00000000000..46784ae8d18 --- /dev/null +++ b/tests/baselines/reference/circularIndexedAccessErrors.js @@ -0,0 +1,70 @@ +//// [circularIndexedAccessErrors.ts] + +type T1 = { + x: T1["x"]; // Error +}; + +type T2 = { + x: T2[K]; // Error + y: number; +} + +declare let x2: T2<"x">; +let x2x = x2.x; + +interface T3> { + x: T["x"]; // Error +} + +interface T4> { + x: T4["x"]; // Error +} + +class C1 { + x: C1["x"]; // Error +} + +class C2 { + x: this["y"]; // Error + y: this["z"]; // Error + z: this["x"]; // Error +} + +//// [circularIndexedAccessErrors.js] +var x2x = x2.x; +var C1 = (function () { + function C1() { + } + return C1; +}()); +var C2 = (function () { + function C2() { + } + return C2; +}()); + + +//// [circularIndexedAccessErrors.d.ts] +declare type T1 = { + x: T1["x"]; +}; +declare type T2 = { + x: T2[K]; + y: number; +}; +declare let x2: T2<"x">; +declare let x2x: any; +interface T3> { + x: T["x"]; +} +interface T4> { + x: T4["x"]; +} +declare class C1 { + x: C1["x"]; +} +declare class C2 { + x: this["y"]; + y: this["z"]; + z: this["x"]; +} diff --git a/tests/baselines/reference/keyofAndIndexedAccess.js b/tests/baselines/reference/keyofAndIndexedAccess.js index a9a5ee29993..4b93897fdc4 100644 --- a/tests/baselines/reference/keyofAndIndexedAccess.js +++ b/tests/baselines/reference/keyofAndIndexedAccess.js @@ -249,6 +249,53 @@ function f74(func: (x: T, y: U, k: K) => (T | U)[ let b = func({ a: 1, b: "hello" }, { a: 2, b: true }, 'b'); // string | boolean } +function f80(obj: T) { + let a1 = obj.a; // { x: any } + let a2 = obj['a']; // { x: any } + let a3 = obj['a'] as T['a']; // T["a"] + let x1 = obj.a.x; // any + let x2 = obj['a']['x']; // any + let x3 = obj['a']['x'] as T['a']['x']; // T["a"]["x"] +} + +function f81(obj: T) { + return obj['a']['x'] as T['a']['x']; +} + +function f82() { + let x1 = f81({ a: { x: "hello" } }); // string + let x2 = f81({ a: { x: 42 } }); // number +} + +function f83(obj: T, key: K) { + return obj[key]['x'] as T[K]['x']; +} + +function f84() { + let x1 = f83({ foo: { x: "hello" } }, "foo"); // string + let x2 = f83({ bar: { x: 42 } }, "bar"); // number +} + +class C1 { + x: number; + get(key: K) { + return this[key]; + } + set(key: K, value: this[K]) { + this[key] = value; + } + foo() { + let x1 = this.x; // number + let x2 = this["x"]; // number + let x3 = this.get("x"); // this["x"] + let x4 = getProperty(this, "x"); // this["x"] + this.x = 42; + this["x"] = 42; + this.set("x", 42); + setProperty(this, "x", 42); + } +} + // Repros from #12011 class Base { @@ -364,7 +411,25 @@ interface R { function f(p: K) { let a: any; a[p].add; // any -} +} + +// Repro from #12651 + +type MethodDescriptor = { + name: string; + args: any[]; + returnValue: any; +} + +declare function dispatchMethod(name: M['name'], args: M['args']): M['returnValue']; + +type SomeMethodDescriptor = { + name: "someMethod"; + args: [string, number]; + returnValue: string[]; +} + +let result = dispatchMethod("someMethod", ["hello", 35]); //// [keyofAndIndexedAccess.js] var __extends = (this && this.__extends) || function (d, b) { @@ -536,6 +601,49 @@ function f74(func) { var a = func({ a: 1, b: "hello" }, { a: 2, b: true }, 'a'); // number var b = func({ a: 1, b: "hello" }, { a: 2, b: true }, 'b'); // string | boolean } +function f80(obj) { + var a1 = obj.a; // { x: any } + var a2 = obj['a']; // { x: any } + var a3 = obj['a']; // T["a"] + var x1 = obj.a.x; // any + var x2 = obj['a']['x']; // any + var x3 = obj['a']['x']; // T["a"]["x"] +} +function f81(obj) { + return obj['a']['x']; +} +function f82() { + var x1 = f81({ a: { x: "hello" } }); // string + var x2 = f81({ a: { x: 42 } }); // number +} +function f83(obj, key) { + return obj[key]['x']; +} +function f84() { + var x1 = f83({ foo: { x: "hello" } }, "foo"); // string + var x2 = f83({ bar: { x: 42 } }, "bar"); // number +} +var C1 = (function () { + function C1() { + } + C1.prototype.get = function (key) { + return this[key]; + }; + C1.prototype.set = function (key, value) { + this[key] = value; + }; + C1.prototype.foo = function () { + var x1 = this.x; // number + var x2 = this["x"]; // number + var x3 = this.get("x"); // this["x"] + var x4 = getProperty(this, "x"); // this["x"] + this.x = 42; + this["x"] = 42; + this.set("x", 42); + setProperty(this, "x", 42); + }; + return C1; +}()); // Repros from #12011 var Base = (function () { function Base() { @@ -604,6 +712,7 @@ function f(p) { var a; a[p].add; // any } +var result = dispatchMethod("someMethod", ["hello", 35]); //// [keyofAndIndexedAccess.d.ts] @@ -716,6 +825,29 @@ declare function f71(func: (x: T, y: U) => Partial): void; declare function f72(func: (x: T, y: U, k: K) => (T & U)[K]): void; declare function f73(func: (x: T, y: U, k: K) => (T & U)[K]): void; declare function f74(func: (x: T, y: U, k: K) => (T | U)[K]): void; +declare function f80(obj: T): void; +declare function f81(obj: T): T["a"]["x"]; +declare function f82(): void; +declare function f83(obj: T, key: K): T[K]["x"]; +declare function f84(): void; +declare class C1 { + x: number; + get(key: K): this[K]; + set(key: K, value: this[K]): void; + foo(): void; +} declare class Base { get(prop: K): this[K]; set(prop: K, value: this[K]): void; @@ -723,12 +855,12 @@ declare class Base { declare class Person extends Base { parts: number; constructor(parts: number); - getParts(): number; + getParts(): this["parts"]; } declare class OtherPerson { parts: number; constructor(parts: number); - getParts(): number; + getParts(): this["parts"]; } declare function path(obj: T, key1: K1): T[K1]; declare function path(obj: T, key1: K1, key2: K2): T[K1][K2]; @@ -776,3 +908,15 @@ interface R { p: number; } declare function f(p: K): void; +declare type MethodDescriptor = { + name: string; + args: any[]; + returnValue: any; +}; +declare function dispatchMethod(name: M['name'], args: M['args']): M['returnValue']; +declare type SomeMethodDescriptor = { + name: "someMethod"; + args: [string, number]; + returnValue: string[]; +}; +declare let result: string[]; diff --git a/tests/baselines/reference/keyofAndIndexedAccess.symbols b/tests/baselines/reference/keyofAndIndexedAccess.symbols index 3d90b4ca276..1c69d4959d8 100644 --- a/tests/baselines/reference/keyofAndIndexedAccess.symbols +++ b/tests/baselines/reference/keyofAndIndexedAccess.symbols @@ -951,396 +951,628 @@ function f74(func: (x: T, y: U, k: K) => (T | U)[ >b : Symbol(b, Decl(keyofAndIndexedAccess.ts, 247, 46)) } +function f80(obj: T) { +>f80 : Symbol(f80, Decl(keyofAndIndexedAccess.ts, 248, 1)) +>T : Symbol(T, Decl(keyofAndIndexedAccess.ts, 250, 13)) +>a : Symbol(a, Decl(keyofAndIndexedAccess.ts, 250, 24)) +>x : Symbol(x, Decl(keyofAndIndexedAccess.ts, 250, 29)) +>obj : Symbol(obj, Decl(keyofAndIndexedAccess.ts, 250, 42)) +>T : Symbol(T, Decl(keyofAndIndexedAccess.ts, 250, 13)) + + let a1 = obj.a; // { x: any } +>a1 : Symbol(a1, Decl(keyofAndIndexedAccess.ts, 251, 7)) +>obj.a : Symbol(a, Decl(keyofAndIndexedAccess.ts, 250, 24)) +>obj : Symbol(obj, Decl(keyofAndIndexedAccess.ts, 250, 42)) +>a : Symbol(a, Decl(keyofAndIndexedAccess.ts, 250, 24)) + + let a2 = obj['a']; // { x: any } +>a2 : Symbol(a2, Decl(keyofAndIndexedAccess.ts, 252, 7)) +>obj : Symbol(obj, Decl(keyofAndIndexedAccess.ts, 250, 42)) +>'a' : Symbol(a, Decl(keyofAndIndexedAccess.ts, 250, 24)) + + let a3 = obj['a'] as T['a']; // T["a"] +>a3 : Symbol(a3, Decl(keyofAndIndexedAccess.ts, 253, 7)) +>obj : Symbol(obj, Decl(keyofAndIndexedAccess.ts, 250, 42)) +>'a' : Symbol(a, Decl(keyofAndIndexedAccess.ts, 250, 24)) +>T : Symbol(T, Decl(keyofAndIndexedAccess.ts, 250, 13)) + + let x1 = obj.a.x; // any +>x1 : Symbol(x1, Decl(keyofAndIndexedAccess.ts, 254, 7)) +>obj.a.x : Symbol(x, Decl(keyofAndIndexedAccess.ts, 250, 29)) +>obj.a : Symbol(a, Decl(keyofAndIndexedAccess.ts, 250, 24)) +>obj : Symbol(obj, Decl(keyofAndIndexedAccess.ts, 250, 42)) +>a : Symbol(a, Decl(keyofAndIndexedAccess.ts, 250, 24)) +>x : Symbol(x, Decl(keyofAndIndexedAccess.ts, 250, 29)) + + let x2 = obj['a']['x']; // any +>x2 : Symbol(x2, Decl(keyofAndIndexedAccess.ts, 255, 7)) +>obj : Symbol(obj, Decl(keyofAndIndexedAccess.ts, 250, 42)) +>'a' : Symbol(a, Decl(keyofAndIndexedAccess.ts, 250, 24)) +>'x' : Symbol(x, Decl(keyofAndIndexedAccess.ts, 250, 29)) + + let x3 = obj['a']['x'] as T['a']['x']; // T["a"]["x"] +>x3 : Symbol(x3, Decl(keyofAndIndexedAccess.ts, 256, 7)) +>obj : Symbol(obj, Decl(keyofAndIndexedAccess.ts, 250, 42)) +>'a' : Symbol(a, Decl(keyofAndIndexedAccess.ts, 250, 24)) +>'x' : Symbol(x, Decl(keyofAndIndexedAccess.ts, 250, 29)) +>T : Symbol(T, Decl(keyofAndIndexedAccess.ts, 250, 13)) +} + +function f81(obj: T) { +>f81 : Symbol(f81, Decl(keyofAndIndexedAccess.ts, 257, 1)) +>T : Symbol(T, Decl(keyofAndIndexedAccess.ts, 259, 13)) +>a : Symbol(a, Decl(keyofAndIndexedAccess.ts, 259, 24)) +>x : Symbol(x, Decl(keyofAndIndexedAccess.ts, 259, 29)) +>obj : Symbol(obj, Decl(keyofAndIndexedAccess.ts, 259, 42)) +>T : Symbol(T, Decl(keyofAndIndexedAccess.ts, 259, 13)) + + return obj['a']['x'] as T['a']['x']; +>obj : Symbol(obj, Decl(keyofAndIndexedAccess.ts, 259, 42)) +>'a' : Symbol(a, Decl(keyofAndIndexedAccess.ts, 259, 24)) +>'x' : Symbol(x, Decl(keyofAndIndexedAccess.ts, 259, 29)) +>T : Symbol(T, Decl(keyofAndIndexedAccess.ts, 259, 13)) +} + +function f82() { +>f82 : Symbol(f82, Decl(keyofAndIndexedAccess.ts, 261, 1)) + + let x1 = f81({ a: { x: "hello" } }); // string +>x1 : Symbol(x1, Decl(keyofAndIndexedAccess.ts, 264, 7)) +>f81 : Symbol(f81, Decl(keyofAndIndexedAccess.ts, 257, 1)) +>a : Symbol(a, Decl(keyofAndIndexedAccess.ts, 264, 18)) +>x : Symbol(x, Decl(keyofAndIndexedAccess.ts, 264, 23)) + + let x2 = f81({ a: { x: 42 } }); // number +>x2 : Symbol(x2, Decl(keyofAndIndexedAccess.ts, 265, 7)) +>f81 : Symbol(f81, Decl(keyofAndIndexedAccess.ts, 257, 1)) +>a : Symbol(a, Decl(keyofAndIndexedAccess.ts, 265, 18)) +>x : Symbol(x, Decl(keyofAndIndexedAccess.ts, 265, 23)) +} + +function f83(obj: T, key: K) { +>f83 : Symbol(f83, Decl(keyofAndIndexedAccess.ts, 266, 1)) +>T : Symbol(T, Decl(keyofAndIndexedAccess.ts, 268, 13)) +>x : Symbol(x, Decl(keyofAndIndexedAccess.ts, 268, 26)) +>x : Symbol(x, Decl(keyofAndIndexedAccess.ts, 268, 39)) +>K : Symbol(K, Decl(keyofAndIndexedAccess.ts, 268, 51)) +>T : Symbol(T, Decl(keyofAndIndexedAccess.ts, 268, 13)) +>obj : Symbol(obj, Decl(keyofAndIndexedAccess.ts, 268, 71)) +>T : Symbol(T, Decl(keyofAndIndexedAccess.ts, 268, 13)) +>key : Symbol(key, Decl(keyofAndIndexedAccess.ts, 268, 78)) +>K : Symbol(K, Decl(keyofAndIndexedAccess.ts, 268, 51)) + + return obj[key]['x'] as T[K]['x']; +>obj : Symbol(obj, Decl(keyofAndIndexedAccess.ts, 268, 71)) +>key : Symbol(key, Decl(keyofAndIndexedAccess.ts, 268, 78)) +>'x' : Symbol(x, Decl(keyofAndIndexedAccess.ts, 268, 39)) +>T : Symbol(T, Decl(keyofAndIndexedAccess.ts, 268, 13)) +>K : Symbol(K, Decl(keyofAndIndexedAccess.ts, 268, 51)) +} + +function f84() { +>f84 : Symbol(f84, Decl(keyofAndIndexedAccess.ts, 270, 1)) + + let x1 = f83({ foo: { x: "hello" } }, "foo"); // string +>x1 : Symbol(x1, Decl(keyofAndIndexedAccess.ts, 273, 7)) +>f83 : Symbol(f83, Decl(keyofAndIndexedAccess.ts, 266, 1)) +>foo : Symbol(foo, Decl(keyofAndIndexedAccess.ts, 273, 18)) +>x : Symbol(x, Decl(keyofAndIndexedAccess.ts, 273, 25)) + + let x2 = f83({ bar: { x: 42 } }, "bar"); // number +>x2 : Symbol(x2, Decl(keyofAndIndexedAccess.ts, 274, 7)) +>f83 : Symbol(f83, Decl(keyofAndIndexedAccess.ts, 266, 1)) +>bar : Symbol(bar, Decl(keyofAndIndexedAccess.ts, 274, 18)) +>x : Symbol(x, Decl(keyofAndIndexedAccess.ts, 274, 25)) +} + +class C1 { +>C1 : Symbol(C1, Decl(keyofAndIndexedAccess.ts, 275, 1)) + + x: number; +>x : Symbol(C1.x, Decl(keyofAndIndexedAccess.ts, 277, 10)) + + get(key: K) { +>get : Symbol(C1.get, Decl(keyofAndIndexedAccess.ts, 278, 14)) +>K : Symbol(K, Decl(keyofAndIndexedAccess.ts, 279, 8)) +>key : Symbol(key, Decl(keyofAndIndexedAccess.ts, 279, 30)) +>K : Symbol(K, Decl(keyofAndIndexedAccess.ts, 279, 8)) + + return this[key]; +>this : Symbol(C1, Decl(keyofAndIndexedAccess.ts, 275, 1)) +>key : Symbol(key, Decl(keyofAndIndexedAccess.ts, 279, 30)) + } + set(key: K, value: this[K]) { +>set : Symbol(C1.set, Decl(keyofAndIndexedAccess.ts, 281, 5)) +>K : Symbol(K, Decl(keyofAndIndexedAccess.ts, 282, 8)) +>key : Symbol(key, Decl(keyofAndIndexedAccess.ts, 282, 30)) +>K : Symbol(K, Decl(keyofAndIndexedAccess.ts, 282, 8)) +>value : Symbol(value, Decl(keyofAndIndexedAccess.ts, 282, 37)) +>K : Symbol(K, Decl(keyofAndIndexedAccess.ts, 282, 8)) + + this[key] = value; +>this : Symbol(C1, Decl(keyofAndIndexedAccess.ts, 275, 1)) +>key : Symbol(key, Decl(keyofAndIndexedAccess.ts, 282, 30)) +>value : Symbol(value, Decl(keyofAndIndexedAccess.ts, 282, 37)) + } + foo() { +>foo : Symbol(C1.foo, Decl(keyofAndIndexedAccess.ts, 284, 5)) + + let x1 = this.x; // number +>x1 : Symbol(x1, Decl(keyofAndIndexedAccess.ts, 286, 11)) +>this.x : Symbol(C1.x, Decl(keyofAndIndexedAccess.ts, 277, 10)) +>this : Symbol(C1, Decl(keyofAndIndexedAccess.ts, 275, 1)) +>x : Symbol(C1.x, Decl(keyofAndIndexedAccess.ts, 277, 10)) + + let x2 = this["x"]; // number +>x2 : Symbol(x2, Decl(keyofAndIndexedAccess.ts, 287, 11)) +>this : Symbol(C1, Decl(keyofAndIndexedAccess.ts, 275, 1)) +>"x" : Symbol(C1.x, Decl(keyofAndIndexedAccess.ts, 277, 10)) + + let x3 = this.get("x"); // this["x"] +>x3 : Symbol(x3, Decl(keyofAndIndexedAccess.ts, 288, 11)) +>this.get : Symbol(C1.get, Decl(keyofAndIndexedAccess.ts, 278, 14)) +>this : Symbol(C1, Decl(keyofAndIndexedAccess.ts, 275, 1)) +>get : Symbol(C1.get, Decl(keyofAndIndexedAccess.ts, 278, 14)) + + let x4 = getProperty(this, "x"); // this["x"] +>x4 : Symbol(x4, Decl(keyofAndIndexedAccess.ts, 289, 11)) +>getProperty : Symbol(getProperty, Decl(keyofAndIndexedAccess.ts, 77, 26)) +>this : Symbol(C1, Decl(keyofAndIndexedAccess.ts, 275, 1)) + + this.x = 42; +>this.x : Symbol(C1.x, Decl(keyofAndIndexedAccess.ts, 277, 10)) +>this : Symbol(C1, Decl(keyofAndIndexedAccess.ts, 275, 1)) +>x : Symbol(C1.x, Decl(keyofAndIndexedAccess.ts, 277, 10)) + + this["x"] = 42; +>this : Symbol(C1, Decl(keyofAndIndexedAccess.ts, 275, 1)) +>"x" : Symbol(C1.x, Decl(keyofAndIndexedAccess.ts, 277, 10)) + + this.set("x", 42); +>this.set : Symbol(C1.set, Decl(keyofAndIndexedAccess.ts, 281, 5)) +>this : Symbol(C1, Decl(keyofAndIndexedAccess.ts, 275, 1)) +>set : Symbol(C1.set, Decl(keyofAndIndexedAccess.ts, 281, 5)) + + setProperty(this, "x", 42); +>setProperty : Symbol(setProperty, Decl(keyofAndIndexedAccess.ts, 81, 1)) +>this : Symbol(C1, Decl(keyofAndIndexedAccess.ts, 275, 1)) + } +} + // Repros from #12011 class Base { ->Base : Symbol(Base, Decl(keyofAndIndexedAccess.ts, 248, 1)) +>Base : Symbol(Base, Decl(keyofAndIndexedAccess.ts, 295, 1)) get(prop: K) { ->get : Symbol(Base.get, Decl(keyofAndIndexedAccess.ts, 252, 12)) ->K : Symbol(K, Decl(keyofAndIndexedAccess.ts, 253, 8)) ->prop : Symbol(prop, Decl(keyofAndIndexedAccess.ts, 253, 30)) ->K : Symbol(K, Decl(keyofAndIndexedAccess.ts, 253, 8)) +>get : Symbol(Base.get, Decl(keyofAndIndexedAccess.ts, 299, 12)) +>K : Symbol(K, Decl(keyofAndIndexedAccess.ts, 300, 8)) +>prop : Symbol(prop, Decl(keyofAndIndexedAccess.ts, 300, 30)) +>K : Symbol(K, Decl(keyofAndIndexedAccess.ts, 300, 8)) return this[prop]; ->this : Symbol(Base, Decl(keyofAndIndexedAccess.ts, 248, 1)) ->prop : Symbol(prop, Decl(keyofAndIndexedAccess.ts, 253, 30)) +>this : Symbol(Base, Decl(keyofAndIndexedAccess.ts, 295, 1)) +>prop : Symbol(prop, Decl(keyofAndIndexedAccess.ts, 300, 30)) } set(prop: K, value: this[K]) { ->set : Symbol(Base.set, Decl(keyofAndIndexedAccess.ts, 255, 5)) ->K : Symbol(K, Decl(keyofAndIndexedAccess.ts, 256, 8)) ->prop : Symbol(prop, Decl(keyofAndIndexedAccess.ts, 256, 30)) ->K : Symbol(K, Decl(keyofAndIndexedAccess.ts, 256, 8)) ->value : Symbol(value, Decl(keyofAndIndexedAccess.ts, 256, 38)) ->K : Symbol(K, Decl(keyofAndIndexedAccess.ts, 256, 8)) +>set : Symbol(Base.set, Decl(keyofAndIndexedAccess.ts, 302, 5)) +>K : Symbol(K, Decl(keyofAndIndexedAccess.ts, 303, 8)) +>prop : Symbol(prop, Decl(keyofAndIndexedAccess.ts, 303, 30)) +>K : Symbol(K, Decl(keyofAndIndexedAccess.ts, 303, 8)) +>value : Symbol(value, Decl(keyofAndIndexedAccess.ts, 303, 38)) +>K : Symbol(K, Decl(keyofAndIndexedAccess.ts, 303, 8)) this[prop] = value; ->this : Symbol(Base, Decl(keyofAndIndexedAccess.ts, 248, 1)) ->prop : Symbol(prop, Decl(keyofAndIndexedAccess.ts, 256, 30)) ->value : Symbol(value, Decl(keyofAndIndexedAccess.ts, 256, 38)) +>this : Symbol(Base, Decl(keyofAndIndexedAccess.ts, 295, 1)) +>prop : Symbol(prop, Decl(keyofAndIndexedAccess.ts, 303, 30)) +>value : Symbol(value, Decl(keyofAndIndexedAccess.ts, 303, 38)) } } class Person extends Base { ->Person : Symbol(Person, Decl(keyofAndIndexedAccess.ts, 259, 1)) ->Base : Symbol(Base, Decl(keyofAndIndexedAccess.ts, 248, 1)) +>Person : Symbol(Person, Decl(keyofAndIndexedAccess.ts, 306, 1)) +>Base : Symbol(Base, Decl(keyofAndIndexedAccess.ts, 295, 1)) parts: number; ->parts : Symbol(Person.parts, Decl(keyofAndIndexedAccess.ts, 261, 27)) +>parts : Symbol(Person.parts, Decl(keyofAndIndexedAccess.ts, 308, 27)) constructor(parts: number) { ->parts : Symbol(parts, Decl(keyofAndIndexedAccess.ts, 263, 16)) +>parts : Symbol(parts, Decl(keyofAndIndexedAccess.ts, 310, 16)) super(); ->super : Symbol(Base, Decl(keyofAndIndexedAccess.ts, 248, 1)) +>super : Symbol(Base, Decl(keyofAndIndexedAccess.ts, 295, 1)) this.set("parts", parts); ->this.set : Symbol(Base.set, Decl(keyofAndIndexedAccess.ts, 255, 5)) ->this : Symbol(Person, Decl(keyofAndIndexedAccess.ts, 259, 1)) ->set : Symbol(Base.set, Decl(keyofAndIndexedAccess.ts, 255, 5)) ->parts : Symbol(parts, Decl(keyofAndIndexedAccess.ts, 263, 16)) +>this.set : Symbol(Base.set, Decl(keyofAndIndexedAccess.ts, 302, 5)) +>this : Symbol(Person, Decl(keyofAndIndexedAccess.ts, 306, 1)) +>set : Symbol(Base.set, Decl(keyofAndIndexedAccess.ts, 302, 5)) +>parts : Symbol(parts, Decl(keyofAndIndexedAccess.ts, 310, 16)) } getParts() { ->getParts : Symbol(Person.getParts, Decl(keyofAndIndexedAccess.ts, 266, 5)) +>getParts : Symbol(Person.getParts, Decl(keyofAndIndexedAccess.ts, 313, 5)) return this.get("parts") ->this.get : Symbol(Base.get, Decl(keyofAndIndexedAccess.ts, 252, 12)) ->this : Symbol(Person, Decl(keyofAndIndexedAccess.ts, 259, 1)) ->get : Symbol(Base.get, Decl(keyofAndIndexedAccess.ts, 252, 12)) +>this.get : Symbol(Base.get, Decl(keyofAndIndexedAccess.ts, 299, 12)) +>this : Symbol(Person, Decl(keyofAndIndexedAccess.ts, 306, 1)) +>get : Symbol(Base.get, Decl(keyofAndIndexedAccess.ts, 299, 12)) } } class OtherPerson { ->OtherPerson : Symbol(OtherPerson, Decl(keyofAndIndexedAccess.ts, 270, 1)) +>OtherPerson : Symbol(OtherPerson, Decl(keyofAndIndexedAccess.ts, 317, 1)) parts: number; ->parts : Symbol(OtherPerson.parts, Decl(keyofAndIndexedAccess.ts, 272, 19)) +>parts : Symbol(OtherPerson.parts, Decl(keyofAndIndexedAccess.ts, 319, 19)) constructor(parts: number) { ->parts : Symbol(parts, Decl(keyofAndIndexedAccess.ts, 274, 16)) +>parts : Symbol(parts, Decl(keyofAndIndexedAccess.ts, 321, 16)) setProperty(this, "parts", parts); >setProperty : Symbol(setProperty, Decl(keyofAndIndexedAccess.ts, 81, 1)) ->this : Symbol(OtherPerson, Decl(keyofAndIndexedAccess.ts, 270, 1)) ->parts : Symbol(parts, Decl(keyofAndIndexedAccess.ts, 274, 16)) +>this : Symbol(OtherPerson, Decl(keyofAndIndexedAccess.ts, 317, 1)) +>parts : Symbol(parts, Decl(keyofAndIndexedAccess.ts, 321, 16)) } getParts() { ->getParts : Symbol(OtherPerson.getParts, Decl(keyofAndIndexedAccess.ts, 276, 5)) +>getParts : Symbol(OtherPerson.getParts, Decl(keyofAndIndexedAccess.ts, 323, 5)) return getProperty(this, "parts") >getProperty : Symbol(getProperty, Decl(keyofAndIndexedAccess.ts, 77, 26)) ->this : Symbol(OtherPerson, Decl(keyofAndIndexedAccess.ts, 270, 1)) +>this : Symbol(OtherPerson, Decl(keyofAndIndexedAccess.ts, 317, 1)) } } // Modified repro from #12544 function path(obj: T, key1: K1): T[K1]; ->path : Symbol(path, Decl(keyofAndIndexedAccess.ts, 280, 1), Decl(keyofAndIndexedAccess.ts, 284, 62), Decl(keyofAndIndexedAccess.ts, 285, 100), Decl(keyofAndIndexedAccess.ts, 286, 142), Decl(keyofAndIndexedAccess.ts, 287, 59)) ->T : Symbol(T, Decl(keyofAndIndexedAccess.ts, 284, 14)) ->K1 : Symbol(K1, Decl(keyofAndIndexedAccess.ts, 284, 16)) ->T : Symbol(T, Decl(keyofAndIndexedAccess.ts, 284, 14)) ->obj : Symbol(obj, Decl(keyofAndIndexedAccess.ts, 284, 37)) ->T : Symbol(T, Decl(keyofAndIndexedAccess.ts, 284, 14)) ->key1 : Symbol(key1, Decl(keyofAndIndexedAccess.ts, 284, 44)) ->K1 : Symbol(K1, Decl(keyofAndIndexedAccess.ts, 284, 16)) ->T : Symbol(T, Decl(keyofAndIndexedAccess.ts, 284, 14)) ->K1 : Symbol(K1, Decl(keyofAndIndexedAccess.ts, 284, 16)) +>path : Symbol(path, Decl(keyofAndIndexedAccess.ts, 327, 1), Decl(keyofAndIndexedAccess.ts, 331, 62), Decl(keyofAndIndexedAccess.ts, 332, 100), Decl(keyofAndIndexedAccess.ts, 333, 142), Decl(keyofAndIndexedAccess.ts, 334, 59)) +>T : Symbol(T, Decl(keyofAndIndexedAccess.ts, 331, 14)) +>K1 : Symbol(K1, Decl(keyofAndIndexedAccess.ts, 331, 16)) +>T : Symbol(T, Decl(keyofAndIndexedAccess.ts, 331, 14)) +>obj : Symbol(obj, Decl(keyofAndIndexedAccess.ts, 331, 37)) +>T : Symbol(T, Decl(keyofAndIndexedAccess.ts, 331, 14)) +>key1 : Symbol(key1, Decl(keyofAndIndexedAccess.ts, 331, 44)) +>K1 : Symbol(K1, Decl(keyofAndIndexedAccess.ts, 331, 16)) +>T : Symbol(T, Decl(keyofAndIndexedAccess.ts, 331, 14)) +>K1 : Symbol(K1, Decl(keyofAndIndexedAccess.ts, 331, 16)) function path(obj: T, key1: K1, key2: K2): T[K1][K2]; ->path : Symbol(path, Decl(keyofAndIndexedAccess.ts, 280, 1), Decl(keyofAndIndexedAccess.ts, 284, 62), Decl(keyofAndIndexedAccess.ts, 285, 100), Decl(keyofAndIndexedAccess.ts, 286, 142), Decl(keyofAndIndexedAccess.ts, 287, 59)) ->T : Symbol(T, Decl(keyofAndIndexedAccess.ts, 285, 14)) ->K1 : Symbol(K1, Decl(keyofAndIndexedAccess.ts, 285, 16)) ->T : Symbol(T, Decl(keyofAndIndexedAccess.ts, 285, 14)) ->K2 : Symbol(K2, Decl(keyofAndIndexedAccess.ts, 285, 36)) ->T : Symbol(T, Decl(keyofAndIndexedAccess.ts, 285, 14)) ->K1 : Symbol(K1, Decl(keyofAndIndexedAccess.ts, 285, 16)) ->obj : Symbol(obj, Decl(keyofAndIndexedAccess.ts, 285, 61)) ->T : Symbol(T, Decl(keyofAndIndexedAccess.ts, 285, 14)) ->key1 : Symbol(key1, Decl(keyofAndIndexedAccess.ts, 285, 68)) ->K1 : Symbol(K1, Decl(keyofAndIndexedAccess.ts, 285, 16)) ->key2 : Symbol(key2, Decl(keyofAndIndexedAccess.ts, 285, 78)) ->K2 : Symbol(K2, Decl(keyofAndIndexedAccess.ts, 285, 36)) ->T : Symbol(T, Decl(keyofAndIndexedAccess.ts, 285, 14)) ->K1 : Symbol(K1, Decl(keyofAndIndexedAccess.ts, 285, 16)) ->K2 : Symbol(K2, Decl(keyofAndIndexedAccess.ts, 285, 36)) +>path : Symbol(path, Decl(keyofAndIndexedAccess.ts, 327, 1), Decl(keyofAndIndexedAccess.ts, 331, 62), Decl(keyofAndIndexedAccess.ts, 332, 100), Decl(keyofAndIndexedAccess.ts, 333, 142), Decl(keyofAndIndexedAccess.ts, 334, 59)) +>T : Symbol(T, Decl(keyofAndIndexedAccess.ts, 332, 14)) +>K1 : Symbol(K1, Decl(keyofAndIndexedAccess.ts, 332, 16)) +>T : Symbol(T, Decl(keyofAndIndexedAccess.ts, 332, 14)) +>K2 : Symbol(K2, Decl(keyofAndIndexedAccess.ts, 332, 36)) +>T : Symbol(T, Decl(keyofAndIndexedAccess.ts, 332, 14)) +>K1 : Symbol(K1, Decl(keyofAndIndexedAccess.ts, 332, 16)) +>obj : Symbol(obj, Decl(keyofAndIndexedAccess.ts, 332, 61)) +>T : Symbol(T, Decl(keyofAndIndexedAccess.ts, 332, 14)) +>key1 : Symbol(key1, Decl(keyofAndIndexedAccess.ts, 332, 68)) +>K1 : Symbol(K1, Decl(keyofAndIndexedAccess.ts, 332, 16)) +>key2 : Symbol(key2, Decl(keyofAndIndexedAccess.ts, 332, 78)) +>K2 : Symbol(K2, Decl(keyofAndIndexedAccess.ts, 332, 36)) +>T : Symbol(T, Decl(keyofAndIndexedAccess.ts, 332, 14)) +>K1 : Symbol(K1, Decl(keyofAndIndexedAccess.ts, 332, 16)) +>K2 : Symbol(K2, Decl(keyofAndIndexedAccess.ts, 332, 36)) function path(obj: T, key1: K1, key2: K2, key3: K3): T[K1][K2][K3]; ->path : Symbol(path, Decl(keyofAndIndexedAccess.ts, 280, 1), Decl(keyofAndIndexedAccess.ts, 284, 62), Decl(keyofAndIndexedAccess.ts, 285, 100), Decl(keyofAndIndexedAccess.ts, 286, 142), Decl(keyofAndIndexedAccess.ts, 287, 59)) ->T : Symbol(T, Decl(keyofAndIndexedAccess.ts, 286, 14)) ->K1 : Symbol(K1, Decl(keyofAndIndexedAccess.ts, 286, 16)) ->T : Symbol(T, Decl(keyofAndIndexedAccess.ts, 286, 14)) ->K2 : Symbol(K2, Decl(keyofAndIndexedAccess.ts, 286, 36)) ->T : Symbol(T, Decl(keyofAndIndexedAccess.ts, 286, 14)) ->K1 : Symbol(K1, Decl(keyofAndIndexedAccess.ts, 286, 16)) ->K3 : Symbol(K3, Decl(keyofAndIndexedAccess.ts, 286, 60)) ->T : Symbol(T, Decl(keyofAndIndexedAccess.ts, 286, 14)) ->K1 : Symbol(K1, Decl(keyofAndIndexedAccess.ts, 286, 16)) ->K2 : Symbol(K2, Decl(keyofAndIndexedAccess.ts, 286, 36)) ->obj : Symbol(obj, Decl(keyofAndIndexedAccess.ts, 286, 89)) ->T : Symbol(T, Decl(keyofAndIndexedAccess.ts, 286, 14)) ->key1 : Symbol(key1, Decl(keyofAndIndexedAccess.ts, 286, 96)) ->K1 : Symbol(K1, Decl(keyofAndIndexedAccess.ts, 286, 16)) ->key2 : Symbol(key2, Decl(keyofAndIndexedAccess.ts, 286, 106)) ->K2 : Symbol(K2, Decl(keyofAndIndexedAccess.ts, 286, 36)) ->key3 : Symbol(key3, Decl(keyofAndIndexedAccess.ts, 286, 116)) ->K3 : Symbol(K3, Decl(keyofAndIndexedAccess.ts, 286, 60)) ->T : Symbol(T, Decl(keyofAndIndexedAccess.ts, 286, 14)) ->K1 : Symbol(K1, Decl(keyofAndIndexedAccess.ts, 286, 16)) ->K2 : Symbol(K2, Decl(keyofAndIndexedAccess.ts, 286, 36)) ->K3 : Symbol(K3, Decl(keyofAndIndexedAccess.ts, 286, 60)) +>path : Symbol(path, Decl(keyofAndIndexedAccess.ts, 327, 1), Decl(keyofAndIndexedAccess.ts, 331, 62), Decl(keyofAndIndexedAccess.ts, 332, 100), Decl(keyofAndIndexedAccess.ts, 333, 142), Decl(keyofAndIndexedAccess.ts, 334, 59)) +>T : Symbol(T, Decl(keyofAndIndexedAccess.ts, 333, 14)) +>K1 : Symbol(K1, Decl(keyofAndIndexedAccess.ts, 333, 16)) +>T : Symbol(T, Decl(keyofAndIndexedAccess.ts, 333, 14)) +>K2 : Symbol(K2, Decl(keyofAndIndexedAccess.ts, 333, 36)) +>T : Symbol(T, Decl(keyofAndIndexedAccess.ts, 333, 14)) +>K1 : Symbol(K1, Decl(keyofAndIndexedAccess.ts, 333, 16)) +>K3 : Symbol(K3, Decl(keyofAndIndexedAccess.ts, 333, 60)) +>T : Symbol(T, Decl(keyofAndIndexedAccess.ts, 333, 14)) +>K1 : Symbol(K1, Decl(keyofAndIndexedAccess.ts, 333, 16)) +>K2 : Symbol(K2, Decl(keyofAndIndexedAccess.ts, 333, 36)) +>obj : Symbol(obj, Decl(keyofAndIndexedAccess.ts, 333, 89)) +>T : Symbol(T, Decl(keyofAndIndexedAccess.ts, 333, 14)) +>key1 : Symbol(key1, Decl(keyofAndIndexedAccess.ts, 333, 96)) +>K1 : Symbol(K1, Decl(keyofAndIndexedAccess.ts, 333, 16)) +>key2 : Symbol(key2, Decl(keyofAndIndexedAccess.ts, 333, 106)) +>K2 : Symbol(K2, Decl(keyofAndIndexedAccess.ts, 333, 36)) +>key3 : Symbol(key3, Decl(keyofAndIndexedAccess.ts, 333, 116)) +>K3 : Symbol(K3, Decl(keyofAndIndexedAccess.ts, 333, 60)) +>T : Symbol(T, Decl(keyofAndIndexedAccess.ts, 333, 14)) +>K1 : Symbol(K1, Decl(keyofAndIndexedAccess.ts, 333, 16)) +>K2 : Symbol(K2, Decl(keyofAndIndexedAccess.ts, 333, 36)) +>K3 : Symbol(K3, Decl(keyofAndIndexedAccess.ts, 333, 60)) function path(obj: any, ...keys: (string | number)[]): any; ->path : Symbol(path, Decl(keyofAndIndexedAccess.ts, 280, 1), Decl(keyofAndIndexedAccess.ts, 284, 62), Decl(keyofAndIndexedAccess.ts, 285, 100), Decl(keyofAndIndexedAccess.ts, 286, 142), Decl(keyofAndIndexedAccess.ts, 287, 59)) ->obj : Symbol(obj, Decl(keyofAndIndexedAccess.ts, 287, 14)) ->keys : Symbol(keys, Decl(keyofAndIndexedAccess.ts, 287, 23)) +>path : Symbol(path, Decl(keyofAndIndexedAccess.ts, 327, 1), Decl(keyofAndIndexedAccess.ts, 331, 62), Decl(keyofAndIndexedAccess.ts, 332, 100), Decl(keyofAndIndexedAccess.ts, 333, 142), Decl(keyofAndIndexedAccess.ts, 334, 59)) +>obj : Symbol(obj, Decl(keyofAndIndexedAccess.ts, 334, 14)) +>keys : Symbol(keys, Decl(keyofAndIndexedAccess.ts, 334, 23)) function path(obj: any, ...keys: (string | number)[]): any { ->path : Symbol(path, Decl(keyofAndIndexedAccess.ts, 280, 1), Decl(keyofAndIndexedAccess.ts, 284, 62), Decl(keyofAndIndexedAccess.ts, 285, 100), Decl(keyofAndIndexedAccess.ts, 286, 142), Decl(keyofAndIndexedAccess.ts, 287, 59)) ->obj : Symbol(obj, Decl(keyofAndIndexedAccess.ts, 288, 14)) ->keys : Symbol(keys, Decl(keyofAndIndexedAccess.ts, 288, 23)) +>path : Symbol(path, Decl(keyofAndIndexedAccess.ts, 327, 1), Decl(keyofAndIndexedAccess.ts, 331, 62), Decl(keyofAndIndexedAccess.ts, 332, 100), Decl(keyofAndIndexedAccess.ts, 333, 142), Decl(keyofAndIndexedAccess.ts, 334, 59)) +>obj : Symbol(obj, Decl(keyofAndIndexedAccess.ts, 335, 14)) +>keys : Symbol(keys, Decl(keyofAndIndexedAccess.ts, 335, 23)) let result = obj; ->result : Symbol(result, Decl(keyofAndIndexedAccess.ts, 289, 7)) ->obj : Symbol(obj, Decl(keyofAndIndexedAccess.ts, 288, 14)) +>result : Symbol(result, Decl(keyofAndIndexedAccess.ts, 336, 7)) +>obj : Symbol(obj, Decl(keyofAndIndexedAccess.ts, 335, 14)) for (let k of keys) { ->k : Symbol(k, Decl(keyofAndIndexedAccess.ts, 290, 12)) ->keys : Symbol(keys, Decl(keyofAndIndexedAccess.ts, 288, 23)) +>k : Symbol(k, Decl(keyofAndIndexedAccess.ts, 337, 12)) +>keys : Symbol(keys, Decl(keyofAndIndexedAccess.ts, 335, 23)) result = result[k]; ->result : Symbol(result, Decl(keyofAndIndexedAccess.ts, 289, 7)) ->result : Symbol(result, Decl(keyofAndIndexedAccess.ts, 289, 7)) ->k : Symbol(k, Decl(keyofAndIndexedAccess.ts, 290, 12)) +>result : Symbol(result, Decl(keyofAndIndexedAccess.ts, 336, 7)) +>result : Symbol(result, Decl(keyofAndIndexedAccess.ts, 336, 7)) +>k : Symbol(k, Decl(keyofAndIndexedAccess.ts, 337, 12)) } return result; ->result : Symbol(result, Decl(keyofAndIndexedAccess.ts, 289, 7)) +>result : Symbol(result, Decl(keyofAndIndexedAccess.ts, 336, 7)) } type Thing = { ->Thing : Symbol(Thing, Decl(keyofAndIndexedAccess.ts, 294, 1)) +>Thing : Symbol(Thing, Decl(keyofAndIndexedAccess.ts, 341, 1)) a: { x: number, y: string }, ->a : Symbol(a, Decl(keyofAndIndexedAccess.ts, 296, 14)) ->x : Symbol(x, Decl(keyofAndIndexedAccess.ts, 297, 8)) ->y : Symbol(y, Decl(keyofAndIndexedAccess.ts, 297, 19)) +>a : Symbol(a, Decl(keyofAndIndexedAccess.ts, 343, 14)) +>x : Symbol(x, Decl(keyofAndIndexedAccess.ts, 344, 8)) +>y : Symbol(y, Decl(keyofAndIndexedAccess.ts, 344, 19)) b: boolean ->b : Symbol(b, Decl(keyofAndIndexedAccess.ts, 297, 32)) +>b : Symbol(b, Decl(keyofAndIndexedAccess.ts, 344, 32)) }; function f1(thing: Thing) { ->f1 : Symbol(f1, Decl(keyofAndIndexedAccess.ts, 299, 2)) ->thing : Symbol(thing, Decl(keyofAndIndexedAccess.ts, 302, 12)) ->Thing : Symbol(Thing, Decl(keyofAndIndexedAccess.ts, 294, 1)) +>f1 : Symbol(f1, Decl(keyofAndIndexedAccess.ts, 346, 2)) +>thing : Symbol(thing, Decl(keyofAndIndexedAccess.ts, 349, 12)) +>Thing : Symbol(Thing, Decl(keyofAndIndexedAccess.ts, 341, 1)) let x1 = path(thing, 'a'); // { x: number, y: string } ->x1 : Symbol(x1, Decl(keyofAndIndexedAccess.ts, 303, 7)) ->path : Symbol(path, Decl(keyofAndIndexedAccess.ts, 280, 1), Decl(keyofAndIndexedAccess.ts, 284, 62), Decl(keyofAndIndexedAccess.ts, 285, 100), Decl(keyofAndIndexedAccess.ts, 286, 142), Decl(keyofAndIndexedAccess.ts, 287, 59)) ->thing : Symbol(thing, Decl(keyofAndIndexedAccess.ts, 302, 12)) +>x1 : Symbol(x1, Decl(keyofAndIndexedAccess.ts, 350, 7)) +>path : Symbol(path, Decl(keyofAndIndexedAccess.ts, 327, 1), Decl(keyofAndIndexedAccess.ts, 331, 62), Decl(keyofAndIndexedAccess.ts, 332, 100), Decl(keyofAndIndexedAccess.ts, 333, 142), Decl(keyofAndIndexedAccess.ts, 334, 59)) +>thing : Symbol(thing, Decl(keyofAndIndexedAccess.ts, 349, 12)) let x2 = path(thing, 'a', 'y'); // string ->x2 : Symbol(x2, Decl(keyofAndIndexedAccess.ts, 304, 7)) ->path : Symbol(path, Decl(keyofAndIndexedAccess.ts, 280, 1), Decl(keyofAndIndexedAccess.ts, 284, 62), Decl(keyofAndIndexedAccess.ts, 285, 100), Decl(keyofAndIndexedAccess.ts, 286, 142), Decl(keyofAndIndexedAccess.ts, 287, 59)) ->thing : Symbol(thing, Decl(keyofAndIndexedAccess.ts, 302, 12)) +>x2 : Symbol(x2, Decl(keyofAndIndexedAccess.ts, 351, 7)) +>path : Symbol(path, Decl(keyofAndIndexedAccess.ts, 327, 1), Decl(keyofAndIndexedAccess.ts, 331, 62), Decl(keyofAndIndexedAccess.ts, 332, 100), Decl(keyofAndIndexedAccess.ts, 333, 142), Decl(keyofAndIndexedAccess.ts, 334, 59)) +>thing : Symbol(thing, Decl(keyofAndIndexedAccess.ts, 349, 12)) let x3 = path(thing, 'b'); // boolean ->x3 : Symbol(x3, Decl(keyofAndIndexedAccess.ts, 305, 7)) ->path : Symbol(path, Decl(keyofAndIndexedAccess.ts, 280, 1), Decl(keyofAndIndexedAccess.ts, 284, 62), Decl(keyofAndIndexedAccess.ts, 285, 100), Decl(keyofAndIndexedAccess.ts, 286, 142), Decl(keyofAndIndexedAccess.ts, 287, 59)) ->thing : Symbol(thing, Decl(keyofAndIndexedAccess.ts, 302, 12)) +>x3 : Symbol(x3, Decl(keyofAndIndexedAccess.ts, 352, 7)) +>path : Symbol(path, Decl(keyofAndIndexedAccess.ts, 327, 1), Decl(keyofAndIndexedAccess.ts, 331, 62), Decl(keyofAndIndexedAccess.ts, 332, 100), Decl(keyofAndIndexedAccess.ts, 333, 142), Decl(keyofAndIndexedAccess.ts, 334, 59)) +>thing : Symbol(thing, Decl(keyofAndIndexedAccess.ts, 349, 12)) let x4 = path(thing, ...['a', 'x']); // any ->x4 : Symbol(x4, Decl(keyofAndIndexedAccess.ts, 306, 7)) ->path : Symbol(path, Decl(keyofAndIndexedAccess.ts, 280, 1), Decl(keyofAndIndexedAccess.ts, 284, 62), Decl(keyofAndIndexedAccess.ts, 285, 100), Decl(keyofAndIndexedAccess.ts, 286, 142), Decl(keyofAndIndexedAccess.ts, 287, 59)) ->thing : Symbol(thing, Decl(keyofAndIndexedAccess.ts, 302, 12)) +>x4 : Symbol(x4, Decl(keyofAndIndexedAccess.ts, 353, 7)) +>path : Symbol(path, Decl(keyofAndIndexedAccess.ts, 327, 1), Decl(keyofAndIndexedAccess.ts, 331, 62), Decl(keyofAndIndexedAccess.ts, 332, 100), Decl(keyofAndIndexedAccess.ts, 333, 142), Decl(keyofAndIndexedAccess.ts, 334, 59)) +>thing : Symbol(thing, Decl(keyofAndIndexedAccess.ts, 349, 12)) } // Repro from comment in #12114 const assignTo2 = (object: T, key1: K1, key2: K2) => ->assignTo2 : Symbol(assignTo2, Decl(keyofAndIndexedAccess.ts, 311, 5)) ->T : Symbol(T, Decl(keyofAndIndexedAccess.ts, 311, 19)) ->K1 : Symbol(K1, Decl(keyofAndIndexedAccess.ts, 311, 21)) ->T : Symbol(T, Decl(keyofAndIndexedAccess.ts, 311, 19)) ->K2 : Symbol(K2, Decl(keyofAndIndexedAccess.ts, 311, 41)) ->T : Symbol(T, Decl(keyofAndIndexedAccess.ts, 311, 19)) ->K1 : Symbol(K1, Decl(keyofAndIndexedAccess.ts, 311, 21)) ->object : Symbol(object, Decl(keyofAndIndexedAccess.ts, 311, 66)) ->T : Symbol(T, Decl(keyofAndIndexedAccess.ts, 311, 19)) ->key1 : Symbol(key1, Decl(keyofAndIndexedAccess.ts, 311, 76)) ->K1 : Symbol(K1, Decl(keyofAndIndexedAccess.ts, 311, 21)) ->key2 : Symbol(key2, Decl(keyofAndIndexedAccess.ts, 311, 86)) ->K2 : Symbol(K2, Decl(keyofAndIndexedAccess.ts, 311, 41)) +>assignTo2 : Symbol(assignTo2, Decl(keyofAndIndexedAccess.ts, 358, 5)) +>T : Symbol(T, Decl(keyofAndIndexedAccess.ts, 358, 19)) +>K1 : Symbol(K1, Decl(keyofAndIndexedAccess.ts, 358, 21)) +>T : Symbol(T, Decl(keyofAndIndexedAccess.ts, 358, 19)) +>K2 : Symbol(K2, Decl(keyofAndIndexedAccess.ts, 358, 41)) +>T : Symbol(T, Decl(keyofAndIndexedAccess.ts, 358, 19)) +>K1 : Symbol(K1, Decl(keyofAndIndexedAccess.ts, 358, 21)) +>object : Symbol(object, Decl(keyofAndIndexedAccess.ts, 358, 66)) +>T : Symbol(T, Decl(keyofAndIndexedAccess.ts, 358, 19)) +>key1 : Symbol(key1, Decl(keyofAndIndexedAccess.ts, 358, 76)) +>K1 : Symbol(K1, Decl(keyofAndIndexedAccess.ts, 358, 21)) +>key2 : Symbol(key2, Decl(keyofAndIndexedAccess.ts, 358, 86)) +>K2 : Symbol(K2, Decl(keyofAndIndexedAccess.ts, 358, 41)) (value: T[K1][K2]) => object[key1][key2] = value; ->value : Symbol(value, Decl(keyofAndIndexedAccess.ts, 312, 5)) ->T : Symbol(T, Decl(keyofAndIndexedAccess.ts, 311, 19)) ->K1 : Symbol(K1, Decl(keyofAndIndexedAccess.ts, 311, 21)) ->K2 : Symbol(K2, Decl(keyofAndIndexedAccess.ts, 311, 41)) ->object : Symbol(object, Decl(keyofAndIndexedAccess.ts, 311, 66)) ->key1 : Symbol(key1, Decl(keyofAndIndexedAccess.ts, 311, 76)) ->key2 : Symbol(key2, Decl(keyofAndIndexedAccess.ts, 311, 86)) ->value : Symbol(value, Decl(keyofAndIndexedAccess.ts, 312, 5)) +>value : Symbol(value, Decl(keyofAndIndexedAccess.ts, 359, 5)) +>T : Symbol(T, Decl(keyofAndIndexedAccess.ts, 358, 19)) +>K1 : Symbol(K1, Decl(keyofAndIndexedAccess.ts, 358, 21)) +>K2 : Symbol(K2, Decl(keyofAndIndexedAccess.ts, 358, 41)) +>object : Symbol(object, Decl(keyofAndIndexedAccess.ts, 358, 66)) +>key1 : Symbol(key1, Decl(keyofAndIndexedAccess.ts, 358, 76)) +>key2 : Symbol(key2, Decl(keyofAndIndexedAccess.ts, 358, 86)) +>value : Symbol(value, Decl(keyofAndIndexedAccess.ts, 359, 5)) // Modified repro from #12573 declare function one(handler: (t: T) => void): T ->one : Symbol(one, Decl(keyofAndIndexedAccess.ts, 312, 53)) ->T : Symbol(T, Decl(keyofAndIndexedAccess.ts, 316, 21)) ->handler : Symbol(handler, Decl(keyofAndIndexedAccess.ts, 316, 24)) ->t : Symbol(t, Decl(keyofAndIndexedAccess.ts, 316, 34)) ->T : Symbol(T, Decl(keyofAndIndexedAccess.ts, 316, 21)) ->T : Symbol(T, Decl(keyofAndIndexedAccess.ts, 316, 21)) +>one : Symbol(one, Decl(keyofAndIndexedAccess.ts, 359, 53)) +>T : Symbol(T, Decl(keyofAndIndexedAccess.ts, 363, 21)) +>handler : Symbol(handler, Decl(keyofAndIndexedAccess.ts, 363, 24)) +>t : Symbol(t, Decl(keyofAndIndexedAccess.ts, 363, 34)) +>T : Symbol(T, Decl(keyofAndIndexedAccess.ts, 363, 21)) +>T : Symbol(T, Decl(keyofAndIndexedAccess.ts, 363, 21)) var empty = one(() => {}) // inferred as {}, expected ->empty : Symbol(empty, Decl(keyofAndIndexedAccess.ts, 317, 3)) ->one : Symbol(one, Decl(keyofAndIndexedAccess.ts, 312, 53)) +>empty : Symbol(empty, Decl(keyofAndIndexedAccess.ts, 364, 3)) +>one : Symbol(one, Decl(keyofAndIndexedAccess.ts, 359, 53)) type Handlers = { [K in keyof T]: (t: T[K]) => void } ->Handlers : Symbol(Handlers, Decl(keyofAndIndexedAccess.ts, 317, 25)) ->T : Symbol(T, Decl(keyofAndIndexedAccess.ts, 319, 14)) ->K : Symbol(K, Decl(keyofAndIndexedAccess.ts, 319, 22)) ->T : Symbol(T, Decl(keyofAndIndexedAccess.ts, 319, 14)) ->t : Symbol(t, Decl(keyofAndIndexedAccess.ts, 319, 38)) ->T : Symbol(T, Decl(keyofAndIndexedAccess.ts, 319, 14)) ->K : Symbol(K, Decl(keyofAndIndexedAccess.ts, 319, 22)) +>Handlers : Symbol(Handlers, Decl(keyofAndIndexedAccess.ts, 364, 25)) +>T : Symbol(T, Decl(keyofAndIndexedAccess.ts, 366, 14)) +>K : Symbol(K, Decl(keyofAndIndexedAccess.ts, 366, 22)) +>T : Symbol(T, Decl(keyofAndIndexedAccess.ts, 366, 14)) +>t : Symbol(t, Decl(keyofAndIndexedAccess.ts, 366, 38)) +>T : Symbol(T, Decl(keyofAndIndexedAccess.ts, 366, 14)) +>K : Symbol(K, Decl(keyofAndIndexedAccess.ts, 366, 22)) declare function on(handlerHash: Handlers): T ->on : Symbol(on, Decl(keyofAndIndexedAccess.ts, 319, 56)) ->T : Symbol(T, Decl(keyofAndIndexedAccess.ts, 320, 20)) ->handlerHash : Symbol(handlerHash, Decl(keyofAndIndexedAccess.ts, 320, 23)) ->Handlers : Symbol(Handlers, Decl(keyofAndIndexedAccess.ts, 317, 25)) ->T : Symbol(T, Decl(keyofAndIndexedAccess.ts, 320, 20)) ->T : Symbol(T, Decl(keyofAndIndexedAccess.ts, 320, 20)) +>on : Symbol(on, Decl(keyofAndIndexedAccess.ts, 366, 56)) +>T : Symbol(T, Decl(keyofAndIndexedAccess.ts, 367, 20)) +>handlerHash : Symbol(handlerHash, Decl(keyofAndIndexedAccess.ts, 367, 23)) +>Handlers : Symbol(Handlers, Decl(keyofAndIndexedAccess.ts, 364, 25)) +>T : Symbol(T, Decl(keyofAndIndexedAccess.ts, 367, 20)) +>T : Symbol(T, Decl(keyofAndIndexedAccess.ts, 367, 20)) var hashOfEmpty1 = on({ test: () => {} }); // {} ->hashOfEmpty1 : Symbol(hashOfEmpty1, Decl(keyofAndIndexedAccess.ts, 321, 3)) ->on : Symbol(on, Decl(keyofAndIndexedAccess.ts, 319, 56)) ->test : Symbol(test, Decl(keyofAndIndexedAccess.ts, 321, 23)) +>hashOfEmpty1 : Symbol(hashOfEmpty1, Decl(keyofAndIndexedAccess.ts, 368, 3)) +>on : Symbol(on, Decl(keyofAndIndexedAccess.ts, 366, 56)) +>test : Symbol(test, Decl(keyofAndIndexedAccess.ts, 368, 23)) var hashOfEmpty2 = on({ test: (x: boolean) => {} }); // { test: boolean } ->hashOfEmpty2 : Symbol(hashOfEmpty2, Decl(keyofAndIndexedAccess.ts, 322, 3)) ->on : Symbol(on, Decl(keyofAndIndexedAccess.ts, 319, 56)) ->test : Symbol(test, Decl(keyofAndIndexedAccess.ts, 322, 23)) ->x : Symbol(x, Decl(keyofAndIndexedAccess.ts, 322, 31)) +>hashOfEmpty2 : Symbol(hashOfEmpty2, Decl(keyofAndIndexedAccess.ts, 369, 3)) +>on : Symbol(on, Decl(keyofAndIndexedAccess.ts, 366, 56)) +>test : Symbol(test, Decl(keyofAndIndexedAccess.ts, 369, 23)) +>x : Symbol(x, Decl(keyofAndIndexedAccess.ts, 369, 31)) // Repro from #12624 interface Options1 { ->Options1 : Symbol(Options1, Decl(keyofAndIndexedAccess.ts, 322, 52)) ->Data : Symbol(Data, Decl(keyofAndIndexedAccess.ts, 326, 19)) ->Computed : Symbol(Computed, Decl(keyofAndIndexedAccess.ts, 326, 24)) +>Options1 : Symbol(Options1, Decl(keyofAndIndexedAccess.ts, 369, 52)) +>Data : Symbol(Data, Decl(keyofAndIndexedAccess.ts, 373, 19)) +>Computed : Symbol(Computed, Decl(keyofAndIndexedAccess.ts, 373, 24)) data?: Data ->data : Symbol(Options1.data, Decl(keyofAndIndexedAccess.ts, 326, 36)) ->Data : Symbol(Data, Decl(keyofAndIndexedAccess.ts, 326, 19)) +>data : Symbol(Options1.data, Decl(keyofAndIndexedAccess.ts, 373, 36)) +>Data : Symbol(Data, Decl(keyofAndIndexedAccess.ts, 373, 19)) computed?: Computed; ->computed : Symbol(Options1.computed, Decl(keyofAndIndexedAccess.ts, 327, 15)) ->Computed : Symbol(Computed, Decl(keyofAndIndexedAccess.ts, 326, 24)) +>computed : Symbol(Options1.computed, Decl(keyofAndIndexedAccess.ts, 374, 15)) +>Computed : Symbol(Computed, Decl(keyofAndIndexedAccess.ts, 373, 24)) } declare class Component1 { ->Component1 : Symbol(Component1, Decl(keyofAndIndexedAccess.ts, 329, 1)) ->Data : Symbol(Data, Decl(keyofAndIndexedAccess.ts, 331, 25)) ->Computed : Symbol(Computed, Decl(keyofAndIndexedAccess.ts, 331, 30)) +>Component1 : Symbol(Component1, Decl(keyofAndIndexedAccess.ts, 376, 1)) +>Data : Symbol(Data, Decl(keyofAndIndexedAccess.ts, 378, 25)) +>Computed : Symbol(Computed, Decl(keyofAndIndexedAccess.ts, 378, 30)) constructor(options: Options1); ->options : Symbol(options, Decl(keyofAndIndexedAccess.ts, 332, 16)) ->Options1 : Symbol(Options1, Decl(keyofAndIndexedAccess.ts, 322, 52)) ->Data : Symbol(Data, Decl(keyofAndIndexedAccess.ts, 331, 25)) ->Computed : Symbol(Computed, Decl(keyofAndIndexedAccess.ts, 331, 30)) +>options : Symbol(options, Decl(keyofAndIndexedAccess.ts, 379, 16)) +>Options1 : Symbol(Options1, Decl(keyofAndIndexedAccess.ts, 369, 52)) +>Data : Symbol(Data, Decl(keyofAndIndexedAccess.ts, 378, 25)) +>Computed : Symbol(Computed, Decl(keyofAndIndexedAccess.ts, 378, 30)) get(key: K): (Data & Computed)[K]; ->get : Symbol(Component1.get, Decl(keyofAndIndexedAccess.ts, 332, 51)) ->K : Symbol(K, Decl(keyofAndIndexedAccess.ts, 333, 8)) ->Data : Symbol(Data, Decl(keyofAndIndexedAccess.ts, 331, 25)) ->Computed : Symbol(Computed, Decl(keyofAndIndexedAccess.ts, 331, 30)) ->key : Symbol(key, Decl(keyofAndIndexedAccess.ts, 333, 43)) ->K : Symbol(K, Decl(keyofAndIndexedAccess.ts, 333, 8)) ->Data : Symbol(Data, Decl(keyofAndIndexedAccess.ts, 331, 25)) ->Computed : Symbol(Computed, Decl(keyofAndIndexedAccess.ts, 331, 30)) ->K : Symbol(K, Decl(keyofAndIndexedAccess.ts, 333, 8)) +>get : Symbol(Component1.get, Decl(keyofAndIndexedAccess.ts, 379, 51)) +>K : Symbol(K, Decl(keyofAndIndexedAccess.ts, 380, 8)) +>Data : Symbol(Data, Decl(keyofAndIndexedAccess.ts, 378, 25)) +>Computed : Symbol(Computed, Decl(keyofAndIndexedAccess.ts, 378, 30)) +>key : Symbol(key, Decl(keyofAndIndexedAccess.ts, 380, 43)) +>K : Symbol(K, Decl(keyofAndIndexedAccess.ts, 380, 8)) +>Data : Symbol(Data, Decl(keyofAndIndexedAccess.ts, 378, 25)) +>Computed : Symbol(Computed, Decl(keyofAndIndexedAccess.ts, 378, 30)) +>K : Symbol(K, Decl(keyofAndIndexedAccess.ts, 380, 8)) } let c1 = new Component1({ ->c1 : Symbol(c1, Decl(keyofAndIndexedAccess.ts, 336, 3)) ->Component1 : Symbol(Component1, Decl(keyofAndIndexedAccess.ts, 329, 1)) +>c1 : Symbol(c1, Decl(keyofAndIndexedAccess.ts, 383, 3)) +>Component1 : Symbol(Component1, Decl(keyofAndIndexedAccess.ts, 376, 1)) data: { ->data : Symbol(data, Decl(keyofAndIndexedAccess.ts, 336, 25)) +>data : Symbol(data, Decl(keyofAndIndexedAccess.ts, 383, 25)) hello: "" ->hello : Symbol(hello, Decl(keyofAndIndexedAccess.ts, 337, 11)) +>hello : Symbol(hello, Decl(keyofAndIndexedAccess.ts, 384, 11)) } }); c1.get("hello"); ->c1.get : Symbol(Component1.get, Decl(keyofAndIndexedAccess.ts, 332, 51)) ->c1 : Symbol(c1, Decl(keyofAndIndexedAccess.ts, 336, 3)) ->get : Symbol(Component1.get, Decl(keyofAndIndexedAccess.ts, 332, 51)) +>c1.get : Symbol(Component1.get, Decl(keyofAndIndexedAccess.ts, 379, 51)) +>c1 : Symbol(c1, Decl(keyofAndIndexedAccess.ts, 383, 3)) +>get : Symbol(Component1.get, Decl(keyofAndIndexedAccess.ts, 379, 51)) // Repro from #12625 interface Options2 { ->Options2 : Symbol(Options2, Decl(keyofAndIndexedAccess.ts, 342, 16)) ->Data : Symbol(Data, Decl(keyofAndIndexedAccess.ts, 346, 19)) ->Computed : Symbol(Computed, Decl(keyofAndIndexedAccess.ts, 346, 24)) +>Options2 : Symbol(Options2, Decl(keyofAndIndexedAccess.ts, 389, 16)) +>Data : Symbol(Data, Decl(keyofAndIndexedAccess.ts, 393, 19)) +>Computed : Symbol(Computed, Decl(keyofAndIndexedAccess.ts, 393, 24)) data?: Data ->data : Symbol(Options2.data, Decl(keyofAndIndexedAccess.ts, 346, 36)) ->Data : Symbol(Data, Decl(keyofAndIndexedAccess.ts, 346, 19)) +>data : Symbol(Options2.data, Decl(keyofAndIndexedAccess.ts, 393, 36)) +>Data : Symbol(Data, Decl(keyofAndIndexedAccess.ts, 393, 19)) computed?: Computed; ->computed : Symbol(Options2.computed, Decl(keyofAndIndexedAccess.ts, 347, 15)) ->Computed : Symbol(Computed, Decl(keyofAndIndexedAccess.ts, 346, 24)) +>computed : Symbol(Options2.computed, Decl(keyofAndIndexedAccess.ts, 394, 15)) +>Computed : Symbol(Computed, Decl(keyofAndIndexedAccess.ts, 393, 24)) } declare class Component2 { ->Component2 : Symbol(Component2, Decl(keyofAndIndexedAccess.ts, 349, 1)) ->Data : Symbol(Data, Decl(keyofAndIndexedAccess.ts, 351, 25)) ->Computed : Symbol(Computed, Decl(keyofAndIndexedAccess.ts, 351, 30)) +>Component2 : Symbol(Component2, Decl(keyofAndIndexedAccess.ts, 396, 1)) +>Data : Symbol(Data, Decl(keyofAndIndexedAccess.ts, 398, 25)) +>Computed : Symbol(Computed, Decl(keyofAndIndexedAccess.ts, 398, 30)) constructor(options: Options2); ->options : Symbol(options, Decl(keyofAndIndexedAccess.ts, 352, 16)) ->Options2 : Symbol(Options2, Decl(keyofAndIndexedAccess.ts, 342, 16)) ->Data : Symbol(Data, Decl(keyofAndIndexedAccess.ts, 351, 25)) ->Computed : Symbol(Computed, Decl(keyofAndIndexedAccess.ts, 351, 30)) +>options : Symbol(options, Decl(keyofAndIndexedAccess.ts, 399, 16)) +>Options2 : Symbol(Options2, Decl(keyofAndIndexedAccess.ts, 389, 16)) +>Data : Symbol(Data, Decl(keyofAndIndexedAccess.ts, 398, 25)) +>Computed : Symbol(Computed, Decl(keyofAndIndexedAccess.ts, 398, 30)) get(key: K): (Data & Computed)[K]; ->get : Symbol(Component2.get, Decl(keyofAndIndexedAccess.ts, 352, 51)) ->K : Symbol(K, Decl(keyofAndIndexedAccess.ts, 353, 8)) ->Data : Symbol(Data, Decl(keyofAndIndexedAccess.ts, 351, 25)) ->Computed : Symbol(Computed, Decl(keyofAndIndexedAccess.ts, 351, 30)) ->key : Symbol(key, Decl(keyofAndIndexedAccess.ts, 353, 47)) ->K : Symbol(K, Decl(keyofAndIndexedAccess.ts, 353, 8)) ->Data : Symbol(Data, Decl(keyofAndIndexedAccess.ts, 351, 25)) ->Computed : Symbol(Computed, Decl(keyofAndIndexedAccess.ts, 351, 30)) ->K : Symbol(K, Decl(keyofAndIndexedAccess.ts, 353, 8)) +>get : Symbol(Component2.get, Decl(keyofAndIndexedAccess.ts, 399, 51)) +>K : Symbol(K, Decl(keyofAndIndexedAccess.ts, 400, 8)) +>Data : Symbol(Data, Decl(keyofAndIndexedAccess.ts, 398, 25)) +>Computed : Symbol(Computed, Decl(keyofAndIndexedAccess.ts, 398, 30)) +>key : Symbol(key, Decl(keyofAndIndexedAccess.ts, 400, 47)) +>K : Symbol(K, Decl(keyofAndIndexedAccess.ts, 400, 8)) +>Data : Symbol(Data, Decl(keyofAndIndexedAccess.ts, 398, 25)) +>Computed : Symbol(Computed, Decl(keyofAndIndexedAccess.ts, 398, 30)) +>K : Symbol(K, Decl(keyofAndIndexedAccess.ts, 400, 8)) } // Repro from #12641 interface R { ->R : Symbol(R, Decl(keyofAndIndexedAccess.ts, 354, 1)) +>R : Symbol(R, Decl(keyofAndIndexedAccess.ts, 401, 1)) p: number; ->p : Symbol(R.p, Decl(keyofAndIndexedAccess.ts, 358, 13)) +>p : Symbol(R.p, Decl(keyofAndIndexedAccess.ts, 405, 13)) } function f(p: K) { ->f : Symbol(f, Decl(keyofAndIndexedAccess.ts, 360, 1)) ->K : Symbol(K, Decl(keyofAndIndexedAccess.ts, 362, 11)) ->R : Symbol(R, Decl(keyofAndIndexedAccess.ts, 354, 1)) ->p : Symbol(p, Decl(keyofAndIndexedAccess.ts, 362, 30)) ->K : Symbol(K, Decl(keyofAndIndexedAccess.ts, 362, 11)) +>f : Symbol(f, Decl(keyofAndIndexedAccess.ts, 407, 1)) +>K : Symbol(K, Decl(keyofAndIndexedAccess.ts, 409, 11)) +>R : Symbol(R, Decl(keyofAndIndexedAccess.ts, 401, 1)) +>p : Symbol(p, Decl(keyofAndIndexedAccess.ts, 409, 30)) +>K : Symbol(K, Decl(keyofAndIndexedAccess.ts, 409, 11)) let a: any; ->a : Symbol(a, Decl(keyofAndIndexedAccess.ts, 363, 7)) +>a : Symbol(a, Decl(keyofAndIndexedAccess.ts, 410, 7)) a[p].add; // any ->a : Symbol(a, Decl(keyofAndIndexedAccess.ts, 363, 7)) ->p : Symbol(p, Decl(keyofAndIndexedAccess.ts, 362, 30)) +>a : Symbol(a, Decl(keyofAndIndexedAccess.ts, 410, 7)) +>p : Symbol(p, Decl(keyofAndIndexedAccess.ts, 409, 30)) } + +// Repro from #12651 + +type MethodDescriptor = { +>MethodDescriptor : Symbol(MethodDescriptor, Decl(keyofAndIndexedAccess.ts, 412, 1)) + + name: string; +>name : Symbol(name, Decl(keyofAndIndexedAccess.ts, 416, 25)) + + args: any[]; +>args : Symbol(args, Decl(keyofAndIndexedAccess.ts, 417, 14)) + + returnValue: any; +>returnValue : Symbol(returnValue, Decl(keyofAndIndexedAccess.ts, 418, 13)) +} + +declare function dispatchMethod(name: M['name'], args: M['args']): M['returnValue']; +>dispatchMethod : Symbol(dispatchMethod, Decl(keyofAndIndexedAccess.ts, 420, 1)) +>M : Symbol(M, Decl(keyofAndIndexedAccess.ts, 422, 32)) +>MethodDescriptor : Symbol(MethodDescriptor, Decl(keyofAndIndexedAccess.ts, 412, 1)) +>name : Symbol(name, Decl(keyofAndIndexedAccess.ts, 422, 60)) +>M : Symbol(M, Decl(keyofAndIndexedAccess.ts, 422, 32)) +>args : Symbol(args, Decl(keyofAndIndexedAccess.ts, 422, 76)) +>M : Symbol(M, Decl(keyofAndIndexedAccess.ts, 422, 32)) +>M : Symbol(M, Decl(keyofAndIndexedAccess.ts, 422, 32)) + +type SomeMethodDescriptor = { +>SomeMethodDescriptor : Symbol(SomeMethodDescriptor, Decl(keyofAndIndexedAccess.ts, 422, 112)) + + name: "someMethod"; +>name : Symbol(name, Decl(keyofAndIndexedAccess.ts, 424, 29)) + + args: [string, number]; +>args : Symbol(args, Decl(keyofAndIndexedAccess.ts, 425, 20)) + + returnValue: string[]; +>returnValue : Symbol(returnValue, Decl(keyofAndIndexedAccess.ts, 426, 24)) +} + +let result = dispatchMethod("someMethod", ["hello", 35]); +>result : Symbol(result, Decl(keyofAndIndexedAccess.ts, 430, 3)) +>dispatchMethod : Symbol(dispatchMethod, Decl(keyofAndIndexedAccess.ts, 420, 1)) +>SomeMethodDescriptor : Symbol(SomeMethodDescriptor, Decl(keyofAndIndexedAccess.ts, 422, 112)) + diff --git a/tests/baselines/reference/keyofAndIndexedAccess.types b/tests/baselines/reference/keyofAndIndexedAccess.types index 3b984643776..f94249806f6 100644 --- a/tests/baselines/reference/keyofAndIndexedAccess.types +++ b/tests/baselines/reference/keyofAndIndexedAccess.types @@ -626,8 +626,8 @@ function f33(shape: S, key: K) { >K : K let name = getProperty(shape, "name"); ->name : string ->getProperty(shape, "name") : string +>name : S["name"] +>getProperty(shape, "name") : S["name"] >getProperty : (obj: T, key: K) => T[K] >shape : S >"name" : "name" @@ -1146,6 +1146,245 @@ function f74(func: (x: T, y: U, k: K) => (T | U)[ >'b' : "b" } +function f80(obj: T) { +>f80 : (obj: T) => void +>T : T +>a : { x: any; } +>x : any +>obj : T +>T : T + + let a1 = obj.a; // { x: any } +>a1 : { x: any; } +>obj.a : { x: any; } +>obj : T +>a : { x: any; } + + let a2 = obj['a']; // { x: any } +>a2 : { x: any; } +>obj['a'] : { x: any; } +>obj : T +>'a' : "a" + + let a3 = obj['a'] as T['a']; // T["a"] +>a3 : T["a"] +>obj['a'] as T['a'] : T["a"] +>obj['a'] : { x: any; } +>obj : T +>'a' : "a" +>T : T + + let x1 = obj.a.x; // any +>x1 : any +>obj.a.x : any +>obj.a : { x: any; } +>obj : T +>a : { x: any; } +>x : any + + let x2 = obj['a']['x']; // any +>x2 : any +>obj['a']['x'] : any +>obj['a'] : { x: any; } +>obj : T +>'a' : "a" +>'x' : "x" + + let x3 = obj['a']['x'] as T['a']['x']; // T["a"]["x"] +>x3 : T["a"]["x"] +>obj['a']['x'] as T['a']['x'] : T["a"]["x"] +>obj['a']['x'] : any +>obj['a'] : { x: any; } +>obj : T +>'a' : "a" +>'x' : "x" +>T : T +} + +function f81(obj: T) { +>f81 : (obj: T) => T["a"]["x"] +>T : T +>a : { x: any; } +>x : any +>obj : T +>T : T + + return obj['a']['x'] as T['a']['x']; +>obj['a']['x'] as T['a']['x'] : T["a"]["x"] +>obj['a']['x'] : any +>obj['a'] : { x: any; } +>obj : T +>'a' : "a" +>'x' : "x" +>T : T +} + +function f82() { +>f82 : () => void + + let x1 = f81({ a: { x: "hello" } }); // string +>x1 : string +>f81({ a: { x: "hello" } }) : string +>f81 : (obj: T) => T["a"]["x"] +>{ a: { x: "hello" } } : { a: { x: string; }; } +>a : { x: string; } +>{ x: "hello" } : { x: string; } +>x : string +>"hello" : "hello" + + let x2 = f81({ a: { x: 42 } }); // number +>x2 : number +>f81({ a: { x: 42 } }) : number +>f81 : (obj: T) => T["a"]["x"] +>{ a: { x: 42 } } : { a: { x: number; }; } +>a : { x: number; } +>{ x: 42 } : { x: number; } +>x : number +>42 : 42 +} + +function f83(obj: T, key: K) { +>f83 : (obj: T, key: K) => T[K]["x"] +>T : T +>x : string +>x : any +>K : K +>T : T +>obj : T +>T : T +>key : K +>K : K + + return obj[key]['x'] as T[K]['x']; +>obj[key]['x'] as T[K]['x'] : T[K]["x"] +>obj[key]['x'] : any +>obj[key] : T[K] +>obj : T +>key : K +>'x' : "x" +>T : T +>K : K +} + +function f84() { +>f84 : () => void + + let x1 = f83({ foo: { x: "hello" } }, "foo"); // string +>x1 : string +>f83({ foo: { x: "hello" } }, "foo") : string +>f83 : (obj: T, key: K) => T[K]["x"] +>{ foo: { x: "hello" } } : { foo: { x: string; }; } +>foo : { x: string; } +>{ x: "hello" } : { x: string; } +>x : string +>"hello" : "hello" +>"foo" : "foo" + + let x2 = f83({ bar: { x: 42 } }, "bar"); // number +>x2 : number +>f83({ bar: { x: 42 } }, "bar") : number +>f83 : (obj: T, key: K) => T[K]["x"] +>{ bar: { x: 42 } } : { bar: { x: number; }; } +>bar : { x: number; } +>{ x: 42 } : { x: number; } +>x : number +>42 : 42 +>"bar" : "bar" +} + +class C1 { +>C1 : C1 + + x: number; +>x : number + + get(key: K) { +>get : (key: K) => this[K] +>K : K +>key : K +>K : K + + return this[key]; +>this[key] : this[K] +>this : this +>key : K + } + set(key: K, value: this[K]) { +>set : (key: K, value: this[K]) => void +>K : K +>key : K +>K : K +>value : this[K] +>K : K + + this[key] = value; +>this[key] = value : this[K] +>this[key] : this[K] +>this : this +>key : K +>value : this[K] + } + foo() { +>foo : () => void + + let x1 = this.x; // number +>x1 : number +>this.x : number +>this : this +>x : number + + let x2 = this["x"]; // number +>x2 : number +>this["x"] : number +>this : this +>"x" : "x" + + let x3 = this.get("x"); // this["x"] +>x3 : this["x"] +>this.get("x") : this["x"] +>this.get : (key: K) => this[K] +>this : this +>get : (key: K) => this[K] +>"x" : "x" + + let x4 = getProperty(this, "x"); // this["x"] +>x4 : this["x"] +>getProperty(this, "x") : this["x"] +>getProperty : (obj: T, key: K) => T[K] +>this : this +>"x" : "x" + + this.x = 42; +>this.x = 42 : 42 +>this.x : number +>this : this +>x : number +>42 : 42 + + this["x"] = 42; +>this["x"] = 42 : 42 +>this["x"] : number +>this : this +>"x" : "x" +>42 : 42 + + this.set("x", 42); +>this.set("x", 42) : void +>this.set : (key: K, value: this[K]) => void +>this : this +>set : (key: K, value: this[K]) => void +>"x" : "x" +>42 : 42 + + setProperty(this, "x", 42); +>setProperty(this, "x", 42) : void +>setProperty : (obj: T, key: K, value: T[K]) => void +>this : this +>"x" : "x" +>42 : 42 + } +} + // Repros from #12011 class Base { @@ -1202,10 +1441,10 @@ class Person extends Base { >parts : number } getParts() { ->getParts : () => number +>getParts : () => this["parts"] return this.get("parts") ->this.get("parts") : number +>this.get("parts") : this["parts"] >this.get : (prop: K) => this[K] >this : this >get : (prop: K) => this[K] @@ -1230,10 +1469,10 @@ class OtherPerson { >parts : number } getParts() { ->getParts : () => number +>getParts : () => this["parts"] return getProperty(this, "parts") ->getProperty(this, "parts") : number +>getProperty(this, "parts") : this["parts"] >getProperty : (obj: T, key: K) => T[K] >this : this >"parts" : "parts" @@ -1587,3 +1826,52 @@ function f(p: K) { >p : K >add : any } + +// Repro from #12651 + +type MethodDescriptor = { +>MethodDescriptor : MethodDescriptor + + name: string; +>name : string + + args: any[]; +>args : any[] + + returnValue: any; +>returnValue : any +} + +declare function dispatchMethod(name: M['name'], args: M['args']): M['returnValue']; +>dispatchMethod : (name: M["name"], args: M["args"]) => M["returnValue"] +>M : M +>MethodDescriptor : MethodDescriptor +>name : M["name"] +>M : M +>args : M["args"] +>M : M +>M : M + +type SomeMethodDescriptor = { +>SomeMethodDescriptor : SomeMethodDescriptor + + name: "someMethod"; +>name : "someMethod" + + args: [string, number]; +>args : [string, number] + + returnValue: string[]; +>returnValue : string[] +} + +let result = dispatchMethod("someMethod", ["hello", 35]); +>result : string[] +>dispatchMethod("someMethod", ["hello", 35]) : string[] +>dispatchMethod : (name: M["name"], args: M["args"]) => M["returnValue"] +>SomeMethodDescriptor : SomeMethodDescriptor +>"someMethod" : "someMethod" +>["hello", 35] : [string, number] +>"hello" : "hello" +>35 : 35 + diff --git a/tests/baselines/reference/keyofIsLiteralContexualType.errors.txt b/tests/baselines/reference/keyofIsLiteralContexualType.errors.txt index 8424d528b22..c19a13209c9 100644 --- a/tests/baselines/reference/keyofIsLiteralContexualType.errors.txt +++ b/tests/baselines/reference/keyofIsLiteralContexualType.errors.txt @@ -1,9 +1,7 @@ tests/cases/compiler/keyofIsLiteralContexualType.ts(5,9): error TS2322: Type '("a" | "b" | "c")[]' is not assignable to type 'keyof T[]'. Type '"a" | "b" | "c"' is not assignable to type 'keyof T'. - Type '"a" | "b" | "c"' is not assignable to type '"a" | "b"'. + Type '"c"' is not assignable to type 'keyof T'. Type '"c"' is not assignable to type '"a" | "b"'. - Type '"c"' is not assignable to type 'keyof T'. - Type '"c"' is not assignable to type '"a" | "b"'. tests/cases/compiler/keyofIsLiteralContexualType.ts(13,11): error TS2339: Property 'b' does not exist on type 'Pick<{ a: number; b: number; c: number; }, "a" | "c">'. @@ -16,10 +14,8 @@ tests/cases/compiler/keyofIsLiteralContexualType.ts(13,11): error TS2339: Proper ~ !!! error TS2322: Type '("a" | "b" | "c")[]' is not assignable to type 'keyof T[]'. !!! error TS2322: Type '"a" | "b" | "c"' is not assignable to type 'keyof T'. -!!! error TS2322: Type '"a" | "b" | "c"' is not assignable to type '"a" | "b"'. +!!! error TS2322: Type '"c"' is not assignable to type 'keyof T'. !!! error TS2322: Type '"c"' is not assignable to type '"a" | "b"'. -!!! error TS2322: Type '"c"' is not assignable to type 'keyof T'. -!!! error TS2322: Type '"c"' is not assignable to type '"a" | "b"'. } // Repro from #12455 diff --git a/tests/baselines/reference/mappedTypeErrors.errors.txt b/tests/baselines/reference/mappedTypeErrors.errors.txt index 918c6627f66..17c77fa50a0 100644 --- a/tests/baselines/reference/mappedTypeErrors.errors.txt +++ b/tests/baselines/reference/mappedTypeErrors.errors.txt @@ -26,9 +26,19 @@ tests/cases/conformance/types/mapped/mappedTypeErrors.ts(78,59): error TS2345: A Object literal may only specify known properties, and 'z' does not exist in type 'Readonly<{ x: number; y: number; }>'. tests/cases/conformance/types/mapped/mappedTypeErrors.ts(84,58): error TS2345: Argument of type '{ x: number; y: number; z: number; }' is not assignable to parameter of type 'Partial<{ x: number; y: number; }>'. Object literal may only specify known properties, and 'z' does not exist in type 'Partial<{ x: number; y: number; }>'. +tests/cases/conformance/types/mapped/mappedTypeErrors.ts(106,15): error TS2345: Argument of type '{ a: undefined; }' is not assignable to parameter of type 'Pick'. + Types of property 'a' are incompatible. + Type 'undefined' is not assignable to type 'string'. +tests/cases/conformance/types/mapped/mappedTypeErrors.ts(107,17): error TS2345: Argument of type '{ c: boolean; }' is not assignable to parameter of type 'Pick'. + Object literal may only specify known properties, and 'c' does not exist in type 'Pick'. +tests/cases/conformance/types/mapped/mappedTypeErrors.ts(124,12): error TS2345: Argument of type '{ a: undefined; }' is not assignable to parameter of type 'Pick'. + Types of property 'a' are incompatible. + Type 'undefined' is not assignable to type 'string'. +tests/cases/conformance/types/mapped/mappedTypeErrors.ts(125,14): error TS2345: Argument of type '{ c: boolean; }' is not assignable to parameter of type 'Pick'. + Object literal may only specify known properties, and 'c' does not exist in type 'Pick'. -==== tests/cases/conformance/types/mapped/mappedTypeErrors.ts (17 errors) ==== +==== tests/cases/conformance/types/mapped/mappedTypeErrors.ts (21 errors) ==== interface Shape { name: string; @@ -158,4 +168,59 @@ tests/cases/conformance/types/mapped/mappedTypeErrors.ts(84,58): error TS2345: A ~~~~ !!! error TS2345: Argument of type '{ x: number; y: number; z: number; }' is not assignable to parameter of type 'Partial<{ x: number; y: number; }>'. !!! error TS2345: Object literal may only specify known properties, and 'z' does not exist in type 'Partial<{ x: number; y: number; }>'. - } \ No newline at end of file + } + + // Verify use of Pick for setState functions (#12793) + + interface Foo { + a: string; + b?: number; + } + + function setState(obj: T, props: Pick) { + for (let k in props) { + obj[k] = props[k]; + } + } + + let foo: Foo = { a: "hello", b: 42 }; + setState(foo, { a: "test", b: 43 }) + setState(foo, { a: "hi" }); + setState(foo, { b: undefined }); + setState(foo, { }); + setState(foo, foo); + setState(foo, { a: undefined }); // Error + ~~~~~~~~~~~~~~~~ +!!! error TS2345: Argument of type '{ a: undefined; }' is not assignable to parameter of type 'Pick'. +!!! error TS2345: Types of property 'a' are incompatible. +!!! error TS2345: Type 'undefined' is not assignable to type 'string'. + setState(foo, { c: true }); // Error + ~~~~~~~ +!!! error TS2345: Argument of type '{ c: boolean; }' is not assignable to parameter of type 'Pick'. +!!! error TS2345: Object literal may only specify known properties, and 'c' does not exist in type 'Pick'. + + class C { + state: T; + setState(props: Pick) { + for (let k in props) { + this.state[k] = props[k]; + } + } + } + + let c = new C(); + c.setState({ a: "test", b: 43 }); + c.setState({ a: "hi" }); + c.setState({ b: undefined }); + c.setState({ }); + c.setState(foo); + c.setState({ a: undefined }); // Error + ~~~~~~~~~~~~~~~~ +!!! error TS2345: Argument of type '{ a: undefined; }' is not assignable to parameter of type 'Pick'. +!!! error TS2345: Types of property 'a' are incompatible. +!!! error TS2345: Type 'undefined' is not assignable to type 'string'. + c.setState({ c: true }); // Error + ~~~~~~~ +!!! error TS2345: Argument of type '{ c: boolean; }' is not assignable to parameter of type 'Pick'. +!!! error TS2345: Object literal may only specify known properties, and 'c' does not exist in type 'Pick'. + \ No newline at end of file diff --git a/tests/baselines/reference/mappedTypeErrors.js b/tests/baselines/reference/mappedTypeErrors.js index 4d2eadbafe9..e1b458565bb 100644 --- a/tests/baselines/reference/mappedTypeErrors.js +++ b/tests/baselines/reference/mappedTypeErrors.js @@ -83,7 +83,48 @@ function f21() { let x1 = objAndPartial({ x: 0, y: 0 }, { x: 1 }); let x2 = objAndPartial({ x: 0, y: 0 }, { x: 1, y: 1 }); let x3 = objAndPartial({ x: 0, y: 0 }, { x: 1, y: 1, z: 1 }); // Error -} +} + +// Verify use of Pick for setState functions (#12793) + +interface Foo { + a: string; + b?: number; +} + +function setState(obj: T, props: Pick) { + for (let k in props) { + obj[k] = props[k]; + } +} + +let foo: Foo = { a: "hello", b: 42 }; +setState(foo, { a: "test", b: 43 }) +setState(foo, { a: "hi" }); +setState(foo, { b: undefined }); +setState(foo, { }); +setState(foo, foo); +setState(foo, { a: undefined }); // Error +setState(foo, { c: true }); // Error + +class C { + state: T; + setState(props: Pick) { + for (let k in props) { + this.state[k] = props[k]; + } + } +} + +let c = new C(); +c.setState({ a: "test", b: 43 }); +c.setState({ a: "hi" }); +c.setState({ b: undefined }); +c.setState({ }); +c.setState(foo); +c.setState({ a: undefined }); // Error +c.setState({ c: true }); // Error + //// [mappedTypeErrors.js] function f1(x) { @@ -124,6 +165,37 @@ function f21() { var x2 = objAndPartial({ x: 0, y: 0 }, { x: 1, y: 1 }); var x3 = objAndPartial({ x: 0, y: 0 }, { x: 1, y: 1, z: 1 }); // Error } +function setState(obj, props) { + for (var k in props) { + obj[k] = props[k]; + } +} +var foo = { a: "hello", b: 42 }; +setState(foo, { a: "test", b: 43 }); +setState(foo, { a: "hi" }); +setState(foo, { b: undefined }); +setState(foo, {}); +setState(foo, foo); +setState(foo, { a: undefined }); // Error +setState(foo, { c: true }); // Error +var C = (function () { + function C() { + } + C.prototype.setState = function (props) { + for (var k in props) { + this.state[k] = props[k]; + } + }; + return C; +}()); +var c = new C(); +c.setState({ a: "test", b: 43 }); +c.setState({ a: "hi" }); +c.setState({ b: undefined }); +c.setState({}); +c.setState(foo); +c.setState({ a: undefined }); // Error +c.setState({ c: true }); // Error //// [mappedTypeErrors.d.ts] @@ -168,3 +240,14 @@ declare function objAndReadonly(primary: T, secondary: Readonly): T; declare function objAndPartial(primary: T, secondary: Partial): T; declare function f20(): void; declare function f21(): void; +interface Foo { + a: string; + b?: number; +} +declare function setState(obj: T, props: Pick): void; +declare let foo: Foo; +declare class C { + state: T; + setState(props: Pick): void; +} +declare let c: C; diff --git a/tests/baselines/reference/mappedTypeModifiers.js b/tests/baselines/reference/mappedTypeModifiers.js index 8489194f95a..9a99441b814 100644 --- a/tests/baselines/reference/mappedTypeModifiers.js +++ b/tests/baselines/reference/mappedTypeModifiers.js @@ -1,145 +1,121 @@ //// [mappedTypeModifiers.ts] type T = { a: number, b: string }; -type TU = { a: number | undefined, b: string | undefined }; type TP = { a?: number, b?: string }; type TR = { readonly a: number, readonly b: string }; type TPR = { readonly a?: number, readonly b?: string }; -// Validate they all have the same keys var v00: "a" | "b"; var v00: keyof T; -var v00: keyof TU; var v00: keyof TP; var v00: keyof TR; var v00: keyof TPR; -// Validate that non-isomorphic mapped types strip modifiers var v01: T; -var v01: Pick; -var v01: Pick, keyof T>; +var v01: { [P in keyof T]: T[P] }; +var v01: Pick; +var v01: Pick, keyof T>; -// Validate that non-isomorphic mapped types strip modifiers -var v02: TU; +var v02: TP; +var v02: { [P in keyof T]?: T[P] }; +var v02: Partial; var v02: Pick; -var v02: Pick; -var v02: Pick, keyof T>; -var v02: Pick>, keyof T>; -// Validate that isomorphic mapped types preserve optional modifier -var v03: TP; -var v03: Partial; +var v03: TR; +var v03: { readonly [P in keyof T]: T[P] }; +var v03: Readonly; +var v03: Pick; -// Validate that isomorphic mapped types preserve readonly modifier -var v04: TR; -var v04: Readonly; - -// Validate that isomorphic mapped types preserve both partial and readonly modifiers -var v05: TPR; -var v05: Partial; -var v05: Readonly; -var v05: Partial>; -var v05: Readonly>; +var v04: TPR; +var v04: { readonly [P in keyof T]?: T[P] }; +var v04: Partial; +var v04: Readonly; +var v04: Partial>; +var v04: Readonly>; +var v04: Pick; type Boxified = { [P in keyof T]: { x: T[P] } }; type B = { a: { x: number }, b: { x: string } }; -type BU = { a: { x: number } | undefined, b: { x: string } | undefined }; type BP = { a?: { x: number }, b?: { x: string } }; type BR = { readonly a: { x: number }, readonly b: { x: string } }; type BPR = { readonly a?: { x: number }, readonly b?: { x: string } }; -// Validate they all have the same keys var b00: "a" | "b"; var b00: keyof B; -var b00: keyof BU; var b00: keyof BP; var b00: keyof BR; var b00: keyof BPR; -// Validate that non-isomorphic mapped types strip modifiers var b01: B; -var b01: Pick; -var b01: Pick, keyof B>; +var b01: { [P in keyof B]: B[P] }; +var b01: Pick; +var b01: Pick, keyof B>; -// Validate that non-isomorphic mapped types strip modifiers -var b02: BU; +var b02: BP; +var b02: { [P in keyof B]?: B[P] }; +var b02: Partial; var b02: Pick; -var b02: Pick; -var b02: Pick, keyof B>; -var b02: Pick>, keyof B>; -// Validate that isomorphic mapped types preserve optional modifier -var b03: BP; -var b03: Partial; +var b03: BR; +var b03: { readonly [P in keyof B]: B[P] }; +var b03: Readonly; +var b03: Pick; -// Validate that isomorphic mapped types preserve readonly modifier -var b04: BR; -var b04: Readonly; - -// Validate that isomorphic mapped types preserve both partial and readonly modifiers -var b05: BPR; -var b05: Partial
; -var b05: Readonly; -var b05: Partial>; -var b05: Readonly>; +var b04: BPR; +var b04: { readonly [P in keyof B]?: B[P] }; +var b04: Partial
; +var b04: Readonly; +var b04: Partial>; +var b04: Readonly>; +var b04: Pick; //// [mappedTypeModifiers.js] -// Validate they all have the same keys var v00; var v00; var v00; var v00; var v00; -var v00; -// Validate that non-isomorphic mapped types strip modifiers var v01; var v01; var v01; -// Validate that non-isomorphic mapped types strip modifiers +var v01; var v02; var v02; var v02; var v02; -var v02; -// Validate that isomorphic mapped types preserve optional modifier var v03; var v03; -// Validate that isomorphic mapped types preserve readonly modifier +var v03; +var v03; +var v04; +var v04; +var v04; +var v04; +var v04; var v04; var v04; -// Validate that isomorphic mapped types preserve both partial and readonly modifiers -var v05; -var v05; -var v05; -var v05; -var v05; -// Validate they all have the same keys var b00; var b00; var b00; var b00; var b00; -var b00; -// Validate that non-isomorphic mapped types strip modifiers var b01; var b01; var b01; -// Validate that non-isomorphic mapped types strip modifiers +var b01; var b02; var b02; var b02; var b02; -var b02; -// Validate that isomorphic mapped types preserve optional modifier var b03; var b03; -// Validate that isomorphic mapped types preserve readonly modifier +var b03; +var b03; +var b04; +var b04; +var b04; +var b04; +var b04; var b04; var b04; -// Validate that isomorphic mapped types preserve both partial and readonly modifiers -var b05; -var b05; -var b05; -var b05; -var b05; diff --git a/tests/baselines/reference/mappedTypeModifiers.symbols b/tests/baselines/reference/mappedTypeModifiers.symbols index 8be2f53cec1..907f8ba8246 100644 --- a/tests/baselines/reference/mappedTypeModifiers.symbols +++ b/tests/baselines/reference/mappedTypeModifiers.symbols @@ -5,309 +5,309 @@ type T = { a: number, b: string }; >a : Symbol(a, Decl(mappedTypeModifiers.ts, 1, 10)) >b : Symbol(b, Decl(mappedTypeModifiers.ts, 1, 21)) -type TU = { a: number | undefined, b: string | undefined }; ->TU : Symbol(TU, Decl(mappedTypeModifiers.ts, 1, 34)) ->a : Symbol(a, Decl(mappedTypeModifiers.ts, 2, 11)) ->b : Symbol(b, Decl(mappedTypeModifiers.ts, 2, 34)) - type TP = { a?: number, b?: string }; ->TP : Symbol(TP, Decl(mappedTypeModifiers.ts, 2, 59)) ->a : Symbol(a, Decl(mappedTypeModifiers.ts, 3, 11)) ->b : Symbol(b, Decl(mappedTypeModifiers.ts, 3, 23)) +>TP : Symbol(TP, Decl(mappedTypeModifiers.ts, 1, 34)) +>a : Symbol(a, Decl(mappedTypeModifiers.ts, 2, 11)) +>b : Symbol(b, Decl(mappedTypeModifiers.ts, 2, 23)) type TR = { readonly a: number, readonly b: string }; ->TR : Symbol(TR, Decl(mappedTypeModifiers.ts, 3, 37)) ->a : Symbol(a, Decl(mappedTypeModifiers.ts, 4, 11)) ->b : Symbol(b, Decl(mappedTypeModifiers.ts, 4, 31)) +>TR : Symbol(TR, Decl(mappedTypeModifiers.ts, 2, 37)) +>a : Symbol(a, Decl(mappedTypeModifiers.ts, 3, 11)) +>b : Symbol(b, Decl(mappedTypeModifiers.ts, 3, 31)) type TPR = { readonly a?: number, readonly b?: string }; ->TPR : Symbol(TPR, Decl(mappedTypeModifiers.ts, 4, 53)) ->a : Symbol(a, Decl(mappedTypeModifiers.ts, 5, 12)) ->b : Symbol(b, Decl(mappedTypeModifiers.ts, 5, 33)) +>TPR : Symbol(TPR, Decl(mappedTypeModifiers.ts, 3, 53)) +>a : Symbol(a, Decl(mappedTypeModifiers.ts, 4, 12)) +>b : Symbol(b, Decl(mappedTypeModifiers.ts, 4, 33)) -// Validate they all have the same keys var v00: "a" | "b"; ->v00 : Symbol(v00, Decl(mappedTypeModifiers.ts, 8, 3), Decl(mappedTypeModifiers.ts, 9, 3), Decl(mappedTypeModifiers.ts, 10, 3), Decl(mappedTypeModifiers.ts, 11, 3), Decl(mappedTypeModifiers.ts, 12, 3), Decl(mappedTypeModifiers.ts, 13, 3)) +>v00 : Symbol(v00, Decl(mappedTypeModifiers.ts, 6, 3), Decl(mappedTypeModifiers.ts, 7, 3), Decl(mappedTypeModifiers.ts, 8, 3), Decl(mappedTypeModifiers.ts, 9, 3), Decl(mappedTypeModifiers.ts, 10, 3)) var v00: keyof T; ->v00 : Symbol(v00, Decl(mappedTypeModifiers.ts, 8, 3), Decl(mappedTypeModifiers.ts, 9, 3), Decl(mappedTypeModifiers.ts, 10, 3), Decl(mappedTypeModifiers.ts, 11, 3), Decl(mappedTypeModifiers.ts, 12, 3), Decl(mappedTypeModifiers.ts, 13, 3)) +>v00 : Symbol(v00, Decl(mappedTypeModifiers.ts, 6, 3), Decl(mappedTypeModifiers.ts, 7, 3), Decl(mappedTypeModifiers.ts, 8, 3), Decl(mappedTypeModifiers.ts, 9, 3), Decl(mappedTypeModifiers.ts, 10, 3)) >T : Symbol(T, Decl(mappedTypeModifiers.ts, 0, 0)) -var v00: keyof TU; ->v00 : Symbol(v00, Decl(mappedTypeModifiers.ts, 8, 3), Decl(mappedTypeModifiers.ts, 9, 3), Decl(mappedTypeModifiers.ts, 10, 3), Decl(mappedTypeModifiers.ts, 11, 3), Decl(mappedTypeModifiers.ts, 12, 3), Decl(mappedTypeModifiers.ts, 13, 3)) ->TU : Symbol(TU, Decl(mappedTypeModifiers.ts, 1, 34)) - var v00: keyof TP; ->v00 : Symbol(v00, Decl(mappedTypeModifiers.ts, 8, 3), Decl(mappedTypeModifiers.ts, 9, 3), Decl(mappedTypeModifiers.ts, 10, 3), Decl(mappedTypeModifiers.ts, 11, 3), Decl(mappedTypeModifiers.ts, 12, 3), Decl(mappedTypeModifiers.ts, 13, 3)) ->TP : Symbol(TP, Decl(mappedTypeModifiers.ts, 2, 59)) +>v00 : Symbol(v00, Decl(mappedTypeModifiers.ts, 6, 3), Decl(mappedTypeModifiers.ts, 7, 3), Decl(mappedTypeModifiers.ts, 8, 3), Decl(mappedTypeModifiers.ts, 9, 3), Decl(mappedTypeModifiers.ts, 10, 3)) +>TP : Symbol(TP, Decl(mappedTypeModifiers.ts, 1, 34)) var v00: keyof TR; ->v00 : Symbol(v00, Decl(mappedTypeModifiers.ts, 8, 3), Decl(mappedTypeModifiers.ts, 9, 3), Decl(mappedTypeModifiers.ts, 10, 3), Decl(mappedTypeModifiers.ts, 11, 3), Decl(mappedTypeModifiers.ts, 12, 3), Decl(mappedTypeModifiers.ts, 13, 3)) ->TR : Symbol(TR, Decl(mappedTypeModifiers.ts, 3, 37)) +>v00 : Symbol(v00, Decl(mappedTypeModifiers.ts, 6, 3), Decl(mappedTypeModifiers.ts, 7, 3), Decl(mappedTypeModifiers.ts, 8, 3), Decl(mappedTypeModifiers.ts, 9, 3), Decl(mappedTypeModifiers.ts, 10, 3)) +>TR : Symbol(TR, Decl(mappedTypeModifiers.ts, 2, 37)) var v00: keyof TPR; ->v00 : Symbol(v00, Decl(mappedTypeModifiers.ts, 8, 3), Decl(mappedTypeModifiers.ts, 9, 3), Decl(mappedTypeModifiers.ts, 10, 3), Decl(mappedTypeModifiers.ts, 11, 3), Decl(mappedTypeModifiers.ts, 12, 3), Decl(mappedTypeModifiers.ts, 13, 3)) ->TPR : Symbol(TPR, Decl(mappedTypeModifiers.ts, 4, 53)) +>v00 : Symbol(v00, Decl(mappedTypeModifiers.ts, 6, 3), Decl(mappedTypeModifiers.ts, 7, 3), Decl(mappedTypeModifiers.ts, 8, 3), Decl(mappedTypeModifiers.ts, 9, 3), Decl(mappedTypeModifiers.ts, 10, 3)) +>TPR : Symbol(TPR, Decl(mappedTypeModifiers.ts, 3, 53)) -// Validate that non-isomorphic mapped types strip modifiers var v01: T; ->v01 : Symbol(v01, Decl(mappedTypeModifiers.ts, 16, 3), Decl(mappedTypeModifiers.ts, 17, 3), Decl(mappedTypeModifiers.ts, 18, 3)) +>v01 : Symbol(v01, Decl(mappedTypeModifiers.ts, 12, 3), Decl(mappedTypeModifiers.ts, 13, 3), Decl(mappedTypeModifiers.ts, 14, 3), Decl(mappedTypeModifiers.ts, 15, 3)) >T : Symbol(T, Decl(mappedTypeModifiers.ts, 0, 0)) -var v01: Pick; ->v01 : Symbol(v01, Decl(mappedTypeModifiers.ts, 16, 3), Decl(mappedTypeModifiers.ts, 17, 3), Decl(mappedTypeModifiers.ts, 18, 3)) +var v01: { [P in keyof T]: T[P] }; +>v01 : Symbol(v01, Decl(mappedTypeModifiers.ts, 12, 3), Decl(mappedTypeModifiers.ts, 13, 3), Decl(mappedTypeModifiers.ts, 14, 3), Decl(mappedTypeModifiers.ts, 15, 3)) +>P : Symbol(P, Decl(mappedTypeModifiers.ts, 13, 12)) +>T : Symbol(T, Decl(mappedTypeModifiers.ts, 0, 0)) +>T : Symbol(T, Decl(mappedTypeModifiers.ts, 0, 0)) +>P : Symbol(P, Decl(mappedTypeModifiers.ts, 13, 12)) + +var v01: Pick; +>v01 : Symbol(v01, Decl(mappedTypeModifiers.ts, 12, 3), Decl(mappedTypeModifiers.ts, 13, 3), Decl(mappedTypeModifiers.ts, 14, 3), Decl(mappedTypeModifiers.ts, 15, 3)) >Pick : Symbol(Pick, Decl(lib.d.ts, --, --)) ->TR : Symbol(TR, Decl(mappedTypeModifiers.ts, 3, 37)) +>T : Symbol(T, Decl(mappedTypeModifiers.ts, 0, 0)) >T : Symbol(T, Decl(mappedTypeModifiers.ts, 0, 0)) -var v01: Pick, keyof T>; ->v01 : Symbol(v01, Decl(mappedTypeModifiers.ts, 16, 3), Decl(mappedTypeModifiers.ts, 17, 3), Decl(mappedTypeModifiers.ts, 18, 3)) +var v01: Pick, keyof T>; +>v01 : Symbol(v01, Decl(mappedTypeModifiers.ts, 12, 3), Decl(mappedTypeModifiers.ts, 13, 3), Decl(mappedTypeModifiers.ts, 14, 3), Decl(mappedTypeModifiers.ts, 15, 3)) >Pick : Symbol(Pick, Decl(lib.d.ts, --, --)) ->Readonly : Symbol(Readonly, Decl(lib.d.ts, --, --)) +>Pick : Symbol(Pick, Decl(lib.d.ts, --, --)) +>T : Symbol(T, Decl(mappedTypeModifiers.ts, 0, 0)) >T : Symbol(T, Decl(mappedTypeModifiers.ts, 0, 0)) >T : Symbol(T, Decl(mappedTypeModifiers.ts, 0, 0)) -// Validate that non-isomorphic mapped types strip modifiers -var v02: TU; ->v02 : Symbol(v02, Decl(mappedTypeModifiers.ts, 21, 3), Decl(mappedTypeModifiers.ts, 22, 3), Decl(mappedTypeModifiers.ts, 23, 3), Decl(mappedTypeModifiers.ts, 24, 3), Decl(mappedTypeModifiers.ts, 25, 3)) ->TU : Symbol(TU, Decl(mappedTypeModifiers.ts, 1, 34)) +var v02: TP; +>v02 : Symbol(v02, Decl(mappedTypeModifiers.ts, 17, 3), Decl(mappedTypeModifiers.ts, 18, 3), Decl(mappedTypeModifiers.ts, 19, 3), Decl(mappedTypeModifiers.ts, 20, 3)) +>TP : Symbol(TP, Decl(mappedTypeModifiers.ts, 1, 34)) + +var v02: { [P in keyof T]?: T[P] }; +>v02 : Symbol(v02, Decl(mappedTypeModifiers.ts, 17, 3), Decl(mappedTypeModifiers.ts, 18, 3), Decl(mappedTypeModifiers.ts, 19, 3), Decl(mappedTypeModifiers.ts, 20, 3)) +>P : Symbol(P, Decl(mappedTypeModifiers.ts, 18, 12)) +>T : Symbol(T, Decl(mappedTypeModifiers.ts, 0, 0)) +>T : Symbol(T, Decl(mappedTypeModifiers.ts, 0, 0)) +>P : Symbol(P, Decl(mappedTypeModifiers.ts, 18, 12)) + +var v02: Partial; +>v02 : Symbol(v02, Decl(mappedTypeModifiers.ts, 17, 3), Decl(mappedTypeModifiers.ts, 18, 3), Decl(mappedTypeModifiers.ts, 19, 3), Decl(mappedTypeModifiers.ts, 20, 3)) +>Partial : Symbol(Partial, Decl(lib.d.ts, --, --)) +>T : Symbol(T, Decl(mappedTypeModifiers.ts, 0, 0)) var v02: Pick; ->v02 : Symbol(v02, Decl(mappedTypeModifiers.ts, 21, 3), Decl(mappedTypeModifiers.ts, 22, 3), Decl(mappedTypeModifiers.ts, 23, 3), Decl(mappedTypeModifiers.ts, 24, 3), Decl(mappedTypeModifiers.ts, 25, 3)) +>v02 : Symbol(v02, Decl(mappedTypeModifiers.ts, 17, 3), Decl(mappedTypeModifiers.ts, 18, 3), Decl(mappedTypeModifiers.ts, 19, 3), Decl(mappedTypeModifiers.ts, 20, 3)) >Pick : Symbol(Pick, Decl(lib.d.ts, --, --)) ->TP : Symbol(TP, Decl(mappedTypeModifiers.ts, 2, 59)) +>TP : Symbol(TP, Decl(mappedTypeModifiers.ts, 1, 34)) >T : Symbol(T, Decl(mappedTypeModifiers.ts, 0, 0)) -var v02: Pick; ->v02 : Symbol(v02, Decl(mappedTypeModifiers.ts, 21, 3), Decl(mappedTypeModifiers.ts, 22, 3), Decl(mappedTypeModifiers.ts, 23, 3), Decl(mappedTypeModifiers.ts, 24, 3), Decl(mappedTypeModifiers.ts, 25, 3)) +var v03: TR; +>v03 : Symbol(v03, Decl(mappedTypeModifiers.ts, 22, 3), Decl(mappedTypeModifiers.ts, 23, 3), Decl(mappedTypeModifiers.ts, 24, 3), Decl(mappedTypeModifiers.ts, 25, 3)) +>TR : Symbol(TR, Decl(mappedTypeModifiers.ts, 2, 37)) + +var v03: { readonly [P in keyof T]: T[P] }; +>v03 : Symbol(v03, Decl(mappedTypeModifiers.ts, 22, 3), Decl(mappedTypeModifiers.ts, 23, 3), Decl(mappedTypeModifiers.ts, 24, 3), Decl(mappedTypeModifiers.ts, 25, 3)) +>P : Symbol(P, Decl(mappedTypeModifiers.ts, 23, 21)) +>T : Symbol(T, Decl(mappedTypeModifiers.ts, 0, 0)) +>T : Symbol(T, Decl(mappedTypeModifiers.ts, 0, 0)) +>P : Symbol(P, Decl(mappedTypeModifiers.ts, 23, 21)) + +var v03: Readonly; +>v03 : Symbol(v03, Decl(mappedTypeModifiers.ts, 22, 3), Decl(mappedTypeModifiers.ts, 23, 3), Decl(mappedTypeModifiers.ts, 24, 3), Decl(mappedTypeModifiers.ts, 25, 3)) +>Readonly : Symbol(Readonly, Decl(lib.d.ts, --, --)) +>T : Symbol(T, Decl(mappedTypeModifiers.ts, 0, 0)) + +var v03: Pick; +>v03 : Symbol(v03, Decl(mappedTypeModifiers.ts, 22, 3), Decl(mappedTypeModifiers.ts, 23, 3), Decl(mappedTypeModifiers.ts, 24, 3), Decl(mappedTypeModifiers.ts, 25, 3)) >Pick : Symbol(Pick, Decl(lib.d.ts, --, --)) ->TPR : Symbol(TPR, Decl(mappedTypeModifiers.ts, 4, 53)) +>TR : Symbol(TR, Decl(mappedTypeModifiers.ts, 2, 37)) >T : Symbol(T, Decl(mappedTypeModifiers.ts, 0, 0)) -var v02: Pick, keyof T>; ->v02 : Symbol(v02, Decl(mappedTypeModifiers.ts, 21, 3), Decl(mappedTypeModifiers.ts, 22, 3), Decl(mappedTypeModifiers.ts, 23, 3), Decl(mappedTypeModifiers.ts, 24, 3), Decl(mappedTypeModifiers.ts, 25, 3)) +var v04: TPR; +>v04 : Symbol(v04, Decl(mappedTypeModifiers.ts, 27, 3), Decl(mappedTypeModifiers.ts, 28, 3), Decl(mappedTypeModifiers.ts, 29, 3), Decl(mappedTypeModifiers.ts, 30, 3), Decl(mappedTypeModifiers.ts, 31, 3), Decl(mappedTypeModifiers.ts, 32, 3), Decl(mappedTypeModifiers.ts, 33, 3)) +>TPR : Symbol(TPR, Decl(mappedTypeModifiers.ts, 3, 53)) + +var v04: { readonly [P in keyof T]?: T[P] }; +>v04 : Symbol(v04, Decl(mappedTypeModifiers.ts, 27, 3), Decl(mappedTypeModifiers.ts, 28, 3), Decl(mappedTypeModifiers.ts, 29, 3), Decl(mappedTypeModifiers.ts, 30, 3), Decl(mappedTypeModifiers.ts, 31, 3), Decl(mappedTypeModifiers.ts, 32, 3), Decl(mappedTypeModifiers.ts, 33, 3)) +>P : Symbol(P, Decl(mappedTypeModifiers.ts, 28, 21)) +>T : Symbol(T, Decl(mappedTypeModifiers.ts, 0, 0)) +>T : Symbol(T, Decl(mappedTypeModifiers.ts, 0, 0)) +>P : Symbol(P, Decl(mappedTypeModifiers.ts, 28, 21)) + +var v04: Partial; +>v04 : Symbol(v04, Decl(mappedTypeModifiers.ts, 27, 3), Decl(mappedTypeModifiers.ts, 28, 3), Decl(mappedTypeModifiers.ts, 29, 3), Decl(mappedTypeModifiers.ts, 30, 3), Decl(mappedTypeModifiers.ts, 31, 3), Decl(mappedTypeModifiers.ts, 32, 3), Decl(mappedTypeModifiers.ts, 33, 3)) +>Partial : Symbol(Partial, Decl(lib.d.ts, --, --)) +>TR : Symbol(TR, Decl(mappedTypeModifiers.ts, 2, 37)) + +var v04: Readonly; +>v04 : Symbol(v04, Decl(mappedTypeModifiers.ts, 27, 3), Decl(mappedTypeModifiers.ts, 28, 3), Decl(mappedTypeModifiers.ts, 29, 3), Decl(mappedTypeModifiers.ts, 30, 3), Decl(mappedTypeModifiers.ts, 31, 3), Decl(mappedTypeModifiers.ts, 32, 3), Decl(mappedTypeModifiers.ts, 33, 3)) +>Readonly : Symbol(Readonly, Decl(lib.d.ts, --, --)) +>TP : Symbol(TP, Decl(mappedTypeModifiers.ts, 1, 34)) + +var v04: Partial>; +>v04 : Symbol(v04, Decl(mappedTypeModifiers.ts, 27, 3), Decl(mappedTypeModifiers.ts, 28, 3), Decl(mappedTypeModifiers.ts, 29, 3), Decl(mappedTypeModifiers.ts, 30, 3), Decl(mappedTypeModifiers.ts, 31, 3), Decl(mappedTypeModifiers.ts, 32, 3), Decl(mappedTypeModifiers.ts, 33, 3)) +>Partial : Symbol(Partial, Decl(lib.d.ts, --, --)) +>Readonly : Symbol(Readonly, Decl(lib.d.ts, --, --)) +>T : Symbol(T, Decl(mappedTypeModifiers.ts, 0, 0)) + +var v04: Readonly>; +>v04 : Symbol(v04, Decl(mappedTypeModifiers.ts, 27, 3), Decl(mappedTypeModifiers.ts, 28, 3), Decl(mappedTypeModifiers.ts, 29, 3), Decl(mappedTypeModifiers.ts, 30, 3), Decl(mappedTypeModifiers.ts, 31, 3), Decl(mappedTypeModifiers.ts, 32, 3), Decl(mappedTypeModifiers.ts, 33, 3)) +>Readonly : Symbol(Readonly, Decl(lib.d.ts, --, --)) +>Partial : Symbol(Partial, Decl(lib.d.ts, --, --)) +>T : Symbol(T, Decl(mappedTypeModifiers.ts, 0, 0)) + +var v04: Pick; +>v04 : Symbol(v04, Decl(mappedTypeModifiers.ts, 27, 3), Decl(mappedTypeModifiers.ts, 28, 3), Decl(mappedTypeModifiers.ts, 29, 3), Decl(mappedTypeModifiers.ts, 30, 3), Decl(mappedTypeModifiers.ts, 31, 3), Decl(mappedTypeModifiers.ts, 32, 3), Decl(mappedTypeModifiers.ts, 33, 3)) >Pick : Symbol(Pick, Decl(lib.d.ts, --, --)) ->Partial : Symbol(Partial, Decl(lib.d.ts, --, --)) ->T : Symbol(T, Decl(mappedTypeModifiers.ts, 0, 0)) ->T : Symbol(T, Decl(mappedTypeModifiers.ts, 0, 0)) - -var v02: Pick>, keyof T>; ->v02 : Symbol(v02, Decl(mappedTypeModifiers.ts, 21, 3), Decl(mappedTypeModifiers.ts, 22, 3), Decl(mappedTypeModifiers.ts, 23, 3), Decl(mappedTypeModifiers.ts, 24, 3), Decl(mappedTypeModifiers.ts, 25, 3)) ->Pick : Symbol(Pick, Decl(lib.d.ts, --, --)) ->Partial : Symbol(Partial, Decl(lib.d.ts, --, --)) ->Readonly : Symbol(Readonly, Decl(lib.d.ts, --, --)) ->T : Symbol(T, Decl(mappedTypeModifiers.ts, 0, 0)) ->T : Symbol(T, Decl(mappedTypeModifiers.ts, 0, 0)) - -// Validate that isomorphic mapped types preserve optional modifier -var v03: TP; ->v03 : Symbol(v03, Decl(mappedTypeModifiers.ts, 28, 3), Decl(mappedTypeModifiers.ts, 29, 3)) ->TP : Symbol(TP, Decl(mappedTypeModifiers.ts, 2, 59)) - -var v03: Partial; ->v03 : Symbol(v03, Decl(mappedTypeModifiers.ts, 28, 3), Decl(mappedTypeModifiers.ts, 29, 3)) ->Partial : Symbol(Partial, Decl(lib.d.ts, --, --)) ->T : Symbol(T, Decl(mappedTypeModifiers.ts, 0, 0)) - -// Validate that isomorphic mapped types preserve readonly modifier -var v04: TR; ->v04 : Symbol(v04, Decl(mappedTypeModifiers.ts, 32, 3), Decl(mappedTypeModifiers.ts, 33, 3)) ->TR : Symbol(TR, Decl(mappedTypeModifiers.ts, 3, 37)) - -var v04: Readonly; ->v04 : Symbol(v04, Decl(mappedTypeModifiers.ts, 32, 3), Decl(mappedTypeModifiers.ts, 33, 3)) ->Readonly : Symbol(Readonly, Decl(lib.d.ts, --, --)) ->T : Symbol(T, Decl(mappedTypeModifiers.ts, 0, 0)) - -// Validate that isomorphic mapped types preserve both partial and readonly modifiers -var v05: TPR; ->v05 : Symbol(v05, Decl(mappedTypeModifiers.ts, 36, 3), Decl(mappedTypeModifiers.ts, 37, 3), Decl(mappedTypeModifiers.ts, 38, 3), Decl(mappedTypeModifiers.ts, 39, 3), Decl(mappedTypeModifiers.ts, 40, 3)) ->TPR : Symbol(TPR, Decl(mappedTypeModifiers.ts, 4, 53)) - -var v05: Partial; ->v05 : Symbol(v05, Decl(mappedTypeModifiers.ts, 36, 3), Decl(mappedTypeModifiers.ts, 37, 3), Decl(mappedTypeModifiers.ts, 38, 3), Decl(mappedTypeModifiers.ts, 39, 3), Decl(mappedTypeModifiers.ts, 40, 3)) ->Partial : Symbol(Partial, Decl(lib.d.ts, --, --)) ->TR : Symbol(TR, Decl(mappedTypeModifiers.ts, 3, 37)) - -var v05: Readonly; ->v05 : Symbol(v05, Decl(mappedTypeModifiers.ts, 36, 3), Decl(mappedTypeModifiers.ts, 37, 3), Decl(mappedTypeModifiers.ts, 38, 3), Decl(mappedTypeModifiers.ts, 39, 3), Decl(mappedTypeModifiers.ts, 40, 3)) ->Readonly : Symbol(Readonly, Decl(lib.d.ts, --, --)) ->TP : Symbol(TP, Decl(mappedTypeModifiers.ts, 2, 59)) - -var v05: Partial>; ->v05 : Symbol(v05, Decl(mappedTypeModifiers.ts, 36, 3), Decl(mappedTypeModifiers.ts, 37, 3), Decl(mappedTypeModifiers.ts, 38, 3), Decl(mappedTypeModifiers.ts, 39, 3), Decl(mappedTypeModifiers.ts, 40, 3)) ->Partial : Symbol(Partial, Decl(lib.d.ts, --, --)) ->Readonly : Symbol(Readonly, Decl(lib.d.ts, --, --)) ->T : Symbol(T, Decl(mappedTypeModifiers.ts, 0, 0)) - -var v05: Readonly>; ->v05 : Symbol(v05, Decl(mappedTypeModifiers.ts, 36, 3), Decl(mappedTypeModifiers.ts, 37, 3), Decl(mappedTypeModifiers.ts, 38, 3), Decl(mappedTypeModifiers.ts, 39, 3), Decl(mappedTypeModifiers.ts, 40, 3)) ->Readonly : Symbol(Readonly, Decl(lib.d.ts, --, --)) ->Partial : Symbol(Partial, Decl(lib.d.ts, --, --)) +>TPR : Symbol(TPR, Decl(mappedTypeModifiers.ts, 3, 53)) >T : Symbol(T, Decl(mappedTypeModifiers.ts, 0, 0)) type Boxified = { [P in keyof T]: { x: T[P] } }; ->Boxified : Symbol(Boxified, Decl(mappedTypeModifiers.ts, 40, 30)) ->T : Symbol(T, Decl(mappedTypeModifiers.ts, 42, 14)) ->P : Symbol(P, Decl(mappedTypeModifiers.ts, 42, 22)) ->T : Symbol(T, Decl(mappedTypeModifiers.ts, 42, 14)) ->x : Symbol(x, Decl(mappedTypeModifiers.ts, 42, 38)) ->T : Symbol(T, Decl(mappedTypeModifiers.ts, 42, 14)) ->P : Symbol(P, Decl(mappedTypeModifiers.ts, 42, 22)) +>Boxified : Symbol(Boxified, Decl(mappedTypeModifiers.ts, 33, 28)) +>T : Symbol(T, Decl(mappedTypeModifiers.ts, 35, 14)) +>P : Symbol(P, Decl(mappedTypeModifiers.ts, 35, 22)) +>T : Symbol(T, Decl(mappedTypeModifiers.ts, 35, 14)) +>x : Symbol(x, Decl(mappedTypeModifiers.ts, 35, 38)) +>T : Symbol(T, Decl(mappedTypeModifiers.ts, 35, 14)) +>P : Symbol(P, Decl(mappedTypeModifiers.ts, 35, 22)) type B = { a: { x: number }, b: { x: string } }; ->B : Symbol(B, Decl(mappedTypeModifiers.ts, 42, 51)) ->a : Symbol(a, Decl(mappedTypeModifiers.ts, 44, 10)) ->x : Symbol(x, Decl(mappedTypeModifiers.ts, 44, 15)) ->b : Symbol(b, Decl(mappedTypeModifiers.ts, 44, 28)) ->x : Symbol(x, Decl(mappedTypeModifiers.ts, 44, 33)) - -type BU = { a: { x: number } | undefined, b: { x: string } | undefined }; ->BU : Symbol(BU, Decl(mappedTypeModifiers.ts, 44, 48)) ->a : Symbol(a, Decl(mappedTypeModifiers.ts, 45, 11)) ->x : Symbol(x, Decl(mappedTypeModifiers.ts, 45, 16)) ->b : Symbol(b, Decl(mappedTypeModifiers.ts, 45, 41)) ->x : Symbol(x, Decl(mappedTypeModifiers.ts, 45, 46)) +>B : Symbol(B, Decl(mappedTypeModifiers.ts, 35, 51)) +>a : Symbol(a, Decl(mappedTypeModifiers.ts, 37, 10)) +>x : Symbol(x, Decl(mappedTypeModifiers.ts, 37, 15)) +>b : Symbol(b, Decl(mappedTypeModifiers.ts, 37, 28)) +>x : Symbol(x, Decl(mappedTypeModifiers.ts, 37, 33)) type BP = { a?: { x: number }, b?: { x: string } }; ->BP : Symbol(BP, Decl(mappedTypeModifiers.ts, 45, 73)) ->a : Symbol(a, Decl(mappedTypeModifiers.ts, 46, 11)) ->x : Symbol(x, Decl(mappedTypeModifiers.ts, 46, 17)) ->b : Symbol(b, Decl(mappedTypeModifiers.ts, 46, 30)) ->x : Symbol(x, Decl(mappedTypeModifiers.ts, 46, 36)) +>BP : Symbol(BP, Decl(mappedTypeModifiers.ts, 37, 48)) +>a : Symbol(a, Decl(mappedTypeModifiers.ts, 38, 11)) +>x : Symbol(x, Decl(mappedTypeModifiers.ts, 38, 17)) +>b : Symbol(b, Decl(mappedTypeModifiers.ts, 38, 30)) +>x : Symbol(x, Decl(mappedTypeModifiers.ts, 38, 36)) type BR = { readonly a: { x: number }, readonly b: { x: string } }; ->BR : Symbol(BR, Decl(mappedTypeModifiers.ts, 46, 51)) ->a : Symbol(a, Decl(mappedTypeModifiers.ts, 47, 11)) ->x : Symbol(x, Decl(mappedTypeModifiers.ts, 47, 25)) ->b : Symbol(b, Decl(mappedTypeModifiers.ts, 47, 38)) ->x : Symbol(x, Decl(mappedTypeModifiers.ts, 47, 52)) +>BR : Symbol(BR, Decl(mappedTypeModifiers.ts, 38, 51)) +>a : Symbol(a, Decl(mappedTypeModifiers.ts, 39, 11)) +>x : Symbol(x, Decl(mappedTypeModifiers.ts, 39, 25)) +>b : Symbol(b, Decl(mappedTypeModifiers.ts, 39, 38)) +>x : Symbol(x, Decl(mappedTypeModifiers.ts, 39, 52)) type BPR = { readonly a?: { x: number }, readonly b?: { x: string } }; ->BPR : Symbol(BPR, Decl(mappedTypeModifiers.ts, 47, 67)) ->a : Symbol(a, Decl(mappedTypeModifiers.ts, 48, 12)) ->x : Symbol(x, Decl(mappedTypeModifiers.ts, 48, 27)) ->b : Symbol(b, Decl(mappedTypeModifiers.ts, 48, 40)) ->x : Symbol(x, Decl(mappedTypeModifiers.ts, 48, 55)) +>BPR : Symbol(BPR, Decl(mappedTypeModifiers.ts, 39, 67)) +>a : Symbol(a, Decl(mappedTypeModifiers.ts, 40, 12)) +>x : Symbol(x, Decl(mappedTypeModifiers.ts, 40, 27)) +>b : Symbol(b, Decl(mappedTypeModifiers.ts, 40, 40)) +>x : Symbol(x, Decl(mappedTypeModifiers.ts, 40, 55)) -// Validate they all have the same keys var b00: "a" | "b"; ->b00 : Symbol(b00, Decl(mappedTypeModifiers.ts, 51, 3), Decl(mappedTypeModifiers.ts, 52, 3), Decl(mappedTypeModifiers.ts, 53, 3), Decl(mappedTypeModifiers.ts, 54, 3), Decl(mappedTypeModifiers.ts, 55, 3), Decl(mappedTypeModifiers.ts, 56, 3)) +>b00 : Symbol(b00, Decl(mappedTypeModifiers.ts, 42, 3), Decl(mappedTypeModifiers.ts, 43, 3), Decl(mappedTypeModifiers.ts, 44, 3), Decl(mappedTypeModifiers.ts, 45, 3), Decl(mappedTypeModifiers.ts, 46, 3)) var b00: keyof B; ->b00 : Symbol(b00, Decl(mappedTypeModifiers.ts, 51, 3), Decl(mappedTypeModifiers.ts, 52, 3), Decl(mappedTypeModifiers.ts, 53, 3), Decl(mappedTypeModifiers.ts, 54, 3), Decl(mappedTypeModifiers.ts, 55, 3), Decl(mappedTypeModifiers.ts, 56, 3)) ->B : Symbol(B, Decl(mappedTypeModifiers.ts, 42, 51)) - -var b00: keyof BU; ->b00 : Symbol(b00, Decl(mappedTypeModifiers.ts, 51, 3), Decl(mappedTypeModifiers.ts, 52, 3), Decl(mappedTypeModifiers.ts, 53, 3), Decl(mappedTypeModifiers.ts, 54, 3), Decl(mappedTypeModifiers.ts, 55, 3), Decl(mappedTypeModifiers.ts, 56, 3)) ->BU : Symbol(BU, Decl(mappedTypeModifiers.ts, 44, 48)) +>b00 : Symbol(b00, Decl(mappedTypeModifiers.ts, 42, 3), Decl(mappedTypeModifiers.ts, 43, 3), Decl(mappedTypeModifiers.ts, 44, 3), Decl(mappedTypeModifiers.ts, 45, 3), Decl(mappedTypeModifiers.ts, 46, 3)) +>B : Symbol(B, Decl(mappedTypeModifiers.ts, 35, 51)) var b00: keyof BP; ->b00 : Symbol(b00, Decl(mappedTypeModifiers.ts, 51, 3), Decl(mappedTypeModifiers.ts, 52, 3), Decl(mappedTypeModifiers.ts, 53, 3), Decl(mappedTypeModifiers.ts, 54, 3), Decl(mappedTypeModifiers.ts, 55, 3), Decl(mappedTypeModifiers.ts, 56, 3)) ->BP : Symbol(BP, Decl(mappedTypeModifiers.ts, 45, 73)) +>b00 : Symbol(b00, Decl(mappedTypeModifiers.ts, 42, 3), Decl(mappedTypeModifiers.ts, 43, 3), Decl(mappedTypeModifiers.ts, 44, 3), Decl(mappedTypeModifiers.ts, 45, 3), Decl(mappedTypeModifiers.ts, 46, 3)) +>BP : Symbol(BP, Decl(mappedTypeModifiers.ts, 37, 48)) var b00: keyof BR; ->b00 : Symbol(b00, Decl(mappedTypeModifiers.ts, 51, 3), Decl(mappedTypeModifiers.ts, 52, 3), Decl(mappedTypeModifiers.ts, 53, 3), Decl(mappedTypeModifiers.ts, 54, 3), Decl(mappedTypeModifiers.ts, 55, 3), Decl(mappedTypeModifiers.ts, 56, 3)) ->BR : Symbol(BR, Decl(mappedTypeModifiers.ts, 46, 51)) +>b00 : Symbol(b00, Decl(mappedTypeModifiers.ts, 42, 3), Decl(mappedTypeModifiers.ts, 43, 3), Decl(mappedTypeModifiers.ts, 44, 3), Decl(mappedTypeModifiers.ts, 45, 3), Decl(mappedTypeModifiers.ts, 46, 3)) +>BR : Symbol(BR, Decl(mappedTypeModifiers.ts, 38, 51)) var b00: keyof BPR; ->b00 : Symbol(b00, Decl(mappedTypeModifiers.ts, 51, 3), Decl(mappedTypeModifiers.ts, 52, 3), Decl(mappedTypeModifiers.ts, 53, 3), Decl(mappedTypeModifiers.ts, 54, 3), Decl(mappedTypeModifiers.ts, 55, 3), Decl(mappedTypeModifiers.ts, 56, 3)) ->BPR : Symbol(BPR, Decl(mappedTypeModifiers.ts, 47, 67)) +>b00 : Symbol(b00, Decl(mappedTypeModifiers.ts, 42, 3), Decl(mappedTypeModifiers.ts, 43, 3), Decl(mappedTypeModifiers.ts, 44, 3), Decl(mappedTypeModifiers.ts, 45, 3), Decl(mappedTypeModifiers.ts, 46, 3)) +>BPR : Symbol(BPR, Decl(mappedTypeModifiers.ts, 39, 67)) -// Validate that non-isomorphic mapped types strip modifiers var b01: B; ->b01 : Symbol(b01, Decl(mappedTypeModifiers.ts, 59, 3), Decl(mappedTypeModifiers.ts, 60, 3), Decl(mappedTypeModifiers.ts, 61, 3)) ->B : Symbol(B, Decl(mappedTypeModifiers.ts, 42, 51)) +>b01 : Symbol(b01, Decl(mappedTypeModifiers.ts, 48, 3), Decl(mappedTypeModifiers.ts, 49, 3), Decl(mappedTypeModifiers.ts, 50, 3), Decl(mappedTypeModifiers.ts, 51, 3)) +>B : Symbol(B, Decl(mappedTypeModifiers.ts, 35, 51)) -var b01: Pick; ->b01 : Symbol(b01, Decl(mappedTypeModifiers.ts, 59, 3), Decl(mappedTypeModifiers.ts, 60, 3), Decl(mappedTypeModifiers.ts, 61, 3)) +var b01: { [P in keyof B]: B[P] }; +>b01 : Symbol(b01, Decl(mappedTypeModifiers.ts, 48, 3), Decl(mappedTypeModifiers.ts, 49, 3), Decl(mappedTypeModifiers.ts, 50, 3), Decl(mappedTypeModifiers.ts, 51, 3)) +>P : Symbol(P, Decl(mappedTypeModifiers.ts, 49, 12)) +>B : Symbol(B, Decl(mappedTypeModifiers.ts, 35, 51)) +>B : Symbol(B, Decl(mappedTypeModifiers.ts, 35, 51)) +>P : Symbol(P, Decl(mappedTypeModifiers.ts, 49, 12)) + +var b01: Pick; +>b01 : Symbol(b01, Decl(mappedTypeModifiers.ts, 48, 3), Decl(mappedTypeModifiers.ts, 49, 3), Decl(mappedTypeModifiers.ts, 50, 3), Decl(mappedTypeModifiers.ts, 51, 3)) >Pick : Symbol(Pick, Decl(lib.d.ts, --, --)) ->BR : Symbol(BR, Decl(mappedTypeModifiers.ts, 46, 51)) ->B : Symbol(B, Decl(mappedTypeModifiers.ts, 42, 51)) +>B : Symbol(B, Decl(mappedTypeModifiers.ts, 35, 51)) +>B : Symbol(B, Decl(mappedTypeModifiers.ts, 35, 51)) -var b01: Pick, keyof B>; ->b01 : Symbol(b01, Decl(mappedTypeModifiers.ts, 59, 3), Decl(mappedTypeModifiers.ts, 60, 3), Decl(mappedTypeModifiers.ts, 61, 3)) +var b01: Pick, keyof B>; +>b01 : Symbol(b01, Decl(mappedTypeModifiers.ts, 48, 3), Decl(mappedTypeModifiers.ts, 49, 3), Decl(mappedTypeModifiers.ts, 50, 3), Decl(mappedTypeModifiers.ts, 51, 3)) >Pick : Symbol(Pick, Decl(lib.d.ts, --, --)) ->Readonly : Symbol(Readonly, Decl(lib.d.ts, --, --)) ->BR : Symbol(BR, Decl(mappedTypeModifiers.ts, 46, 51)) ->B : Symbol(B, Decl(mappedTypeModifiers.ts, 42, 51)) +>Pick : Symbol(Pick, Decl(lib.d.ts, --, --)) +>B : Symbol(B, Decl(mappedTypeModifiers.ts, 35, 51)) +>B : Symbol(B, Decl(mappedTypeModifiers.ts, 35, 51)) +>B : Symbol(B, Decl(mappedTypeModifiers.ts, 35, 51)) -// Validate that non-isomorphic mapped types strip modifiers -var b02: BU; ->b02 : Symbol(b02, Decl(mappedTypeModifiers.ts, 64, 3), Decl(mappedTypeModifiers.ts, 65, 3), Decl(mappedTypeModifiers.ts, 66, 3), Decl(mappedTypeModifiers.ts, 67, 3), Decl(mappedTypeModifiers.ts, 68, 3)) ->BU : Symbol(BU, Decl(mappedTypeModifiers.ts, 44, 48)) +var b02: BP; +>b02 : Symbol(b02, Decl(mappedTypeModifiers.ts, 53, 3), Decl(mappedTypeModifiers.ts, 54, 3), Decl(mappedTypeModifiers.ts, 55, 3), Decl(mappedTypeModifiers.ts, 56, 3)) +>BP : Symbol(BP, Decl(mappedTypeModifiers.ts, 37, 48)) + +var b02: { [P in keyof B]?: B[P] }; +>b02 : Symbol(b02, Decl(mappedTypeModifiers.ts, 53, 3), Decl(mappedTypeModifiers.ts, 54, 3), Decl(mappedTypeModifiers.ts, 55, 3), Decl(mappedTypeModifiers.ts, 56, 3)) +>P : Symbol(P, Decl(mappedTypeModifiers.ts, 54, 12)) +>B : Symbol(B, Decl(mappedTypeModifiers.ts, 35, 51)) +>B : Symbol(B, Decl(mappedTypeModifiers.ts, 35, 51)) +>P : Symbol(P, Decl(mappedTypeModifiers.ts, 54, 12)) + +var b02: Partial; +>b02 : Symbol(b02, Decl(mappedTypeModifiers.ts, 53, 3), Decl(mappedTypeModifiers.ts, 54, 3), Decl(mappedTypeModifiers.ts, 55, 3), Decl(mappedTypeModifiers.ts, 56, 3)) +>Partial : Symbol(Partial, Decl(lib.d.ts, --, --)) +>B : Symbol(B, Decl(mappedTypeModifiers.ts, 35, 51)) var b02: Pick; ->b02 : Symbol(b02, Decl(mappedTypeModifiers.ts, 64, 3), Decl(mappedTypeModifiers.ts, 65, 3), Decl(mappedTypeModifiers.ts, 66, 3), Decl(mappedTypeModifiers.ts, 67, 3), Decl(mappedTypeModifiers.ts, 68, 3)) +>b02 : Symbol(b02, Decl(mappedTypeModifiers.ts, 53, 3), Decl(mappedTypeModifiers.ts, 54, 3), Decl(mappedTypeModifiers.ts, 55, 3), Decl(mappedTypeModifiers.ts, 56, 3)) >Pick : Symbol(Pick, Decl(lib.d.ts, --, --)) ->BP : Symbol(BP, Decl(mappedTypeModifiers.ts, 45, 73)) ->B : Symbol(B, Decl(mappedTypeModifiers.ts, 42, 51)) +>BP : Symbol(BP, Decl(mappedTypeModifiers.ts, 37, 48)) +>B : Symbol(B, Decl(mappedTypeModifiers.ts, 35, 51)) -var b02: Pick; ->b02 : Symbol(b02, Decl(mappedTypeModifiers.ts, 64, 3), Decl(mappedTypeModifiers.ts, 65, 3), Decl(mappedTypeModifiers.ts, 66, 3), Decl(mappedTypeModifiers.ts, 67, 3), Decl(mappedTypeModifiers.ts, 68, 3)) +var b03: BR; +>b03 : Symbol(b03, Decl(mappedTypeModifiers.ts, 58, 3), Decl(mappedTypeModifiers.ts, 59, 3), Decl(mappedTypeModifiers.ts, 60, 3), Decl(mappedTypeModifiers.ts, 61, 3)) +>BR : Symbol(BR, Decl(mappedTypeModifiers.ts, 38, 51)) + +var b03: { readonly [P in keyof B]: B[P] }; +>b03 : Symbol(b03, Decl(mappedTypeModifiers.ts, 58, 3), Decl(mappedTypeModifiers.ts, 59, 3), Decl(mappedTypeModifiers.ts, 60, 3), Decl(mappedTypeModifiers.ts, 61, 3)) +>P : Symbol(P, Decl(mappedTypeModifiers.ts, 59, 21)) +>B : Symbol(B, Decl(mappedTypeModifiers.ts, 35, 51)) +>B : Symbol(B, Decl(mappedTypeModifiers.ts, 35, 51)) +>P : Symbol(P, Decl(mappedTypeModifiers.ts, 59, 21)) + +var b03: Readonly; +>b03 : Symbol(b03, Decl(mappedTypeModifiers.ts, 58, 3), Decl(mappedTypeModifiers.ts, 59, 3), Decl(mappedTypeModifiers.ts, 60, 3), Decl(mappedTypeModifiers.ts, 61, 3)) +>Readonly : Symbol(Readonly, Decl(lib.d.ts, --, --)) +>B : Symbol(B, Decl(mappedTypeModifiers.ts, 35, 51)) + +var b03: Pick; +>b03 : Symbol(b03, Decl(mappedTypeModifiers.ts, 58, 3), Decl(mappedTypeModifiers.ts, 59, 3), Decl(mappedTypeModifiers.ts, 60, 3), Decl(mappedTypeModifiers.ts, 61, 3)) >Pick : Symbol(Pick, Decl(lib.d.ts, --, --)) ->BPR : Symbol(BPR, Decl(mappedTypeModifiers.ts, 47, 67)) ->B : Symbol(B, Decl(mappedTypeModifiers.ts, 42, 51)) +>BR : Symbol(BR, Decl(mappedTypeModifiers.ts, 38, 51)) +>B : Symbol(B, Decl(mappedTypeModifiers.ts, 35, 51)) -var b02: Pick, keyof B>; ->b02 : Symbol(b02, Decl(mappedTypeModifiers.ts, 64, 3), Decl(mappedTypeModifiers.ts, 65, 3), Decl(mappedTypeModifiers.ts, 66, 3), Decl(mappedTypeModifiers.ts, 67, 3), Decl(mappedTypeModifiers.ts, 68, 3)) +var b04: BPR; +>b04 : Symbol(b04, Decl(mappedTypeModifiers.ts, 63, 3), Decl(mappedTypeModifiers.ts, 64, 3), Decl(mappedTypeModifiers.ts, 65, 3), Decl(mappedTypeModifiers.ts, 66, 3), Decl(mappedTypeModifiers.ts, 67, 3), Decl(mappedTypeModifiers.ts, 68, 3), Decl(mappedTypeModifiers.ts, 69, 3)) +>BPR : Symbol(BPR, Decl(mappedTypeModifiers.ts, 39, 67)) + +var b04: { readonly [P in keyof B]?: B[P] }; +>b04 : Symbol(b04, Decl(mappedTypeModifiers.ts, 63, 3), Decl(mappedTypeModifiers.ts, 64, 3), Decl(mappedTypeModifiers.ts, 65, 3), Decl(mappedTypeModifiers.ts, 66, 3), Decl(mappedTypeModifiers.ts, 67, 3), Decl(mappedTypeModifiers.ts, 68, 3), Decl(mappedTypeModifiers.ts, 69, 3)) +>P : Symbol(P, Decl(mappedTypeModifiers.ts, 64, 21)) +>B : Symbol(B, Decl(mappedTypeModifiers.ts, 35, 51)) +>B : Symbol(B, Decl(mappedTypeModifiers.ts, 35, 51)) +>P : Symbol(P, Decl(mappedTypeModifiers.ts, 64, 21)) + +var b04: Partial
; +>b04 : Symbol(b04, Decl(mappedTypeModifiers.ts, 63, 3), Decl(mappedTypeModifiers.ts, 64, 3), Decl(mappedTypeModifiers.ts, 65, 3), Decl(mappedTypeModifiers.ts, 66, 3), Decl(mappedTypeModifiers.ts, 67, 3), Decl(mappedTypeModifiers.ts, 68, 3), Decl(mappedTypeModifiers.ts, 69, 3)) +>Partial : Symbol(Partial, Decl(lib.d.ts, --, --)) +>BR : Symbol(BR, Decl(mappedTypeModifiers.ts, 38, 51)) + +var b04: Readonly; +>b04 : Symbol(b04, Decl(mappedTypeModifiers.ts, 63, 3), Decl(mappedTypeModifiers.ts, 64, 3), Decl(mappedTypeModifiers.ts, 65, 3), Decl(mappedTypeModifiers.ts, 66, 3), Decl(mappedTypeModifiers.ts, 67, 3), Decl(mappedTypeModifiers.ts, 68, 3), Decl(mappedTypeModifiers.ts, 69, 3)) +>Readonly : Symbol(Readonly, Decl(lib.d.ts, --, --)) +>BP : Symbol(BP, Decl(mappedTypeModifiers.ts, 37, 48)) + +var b04: Partial>; +>b04 : Symbol(b04, Decl(mappedTypeModifiers.ts, 63, 3), Decl(mappedTypeModifiers.ts, 64, 3), Decl(mappedTypeModifiers.ts, 65, 3), Decl(mappedTypeModifiers.ts, 66, 3), Decl(mappedTypeModifiers.ts, 67, 3), Decl(mappedTypeModifiers.ts, 68, 3), Decl(mappedTypeModifiers.ts, 69, 3)) +>Partial : Symbol(Partial, Decl(lib.d.ts, --, --)) +>Readonly : Symbol(Readonly, Decl(lib.d.ts, --, --)) +>B : Symbol(B, Decl(mappedTypeModifiers.ts, 35, 51)) + +var b04: Readonly>; +>b04 : Symbol(b04, Decl(mappedTypeModifiers.ts, 63, 3), Decl(mappedTypeModifiers.ts, 64, 3), Decl(mappedTypeModifiers.ts, 65, 3), Decl(mappedTypeModifiers.ts, 66, 3), Decl(mappedTypeModifiers.ts, 67, 3), Decl(mappedTypeModifiers.ts, 68, 3), Decl(mappedTypeModifiers.ts, 69, 3)) +>Readonly : Symbol(Readonly, Decl(lib.d.ts, --, --)) +>Partial : Symbol(Partial, Decl(lib.d.ts, --, --)) +>B : Symbol(B, Decl(mappedTypeModifiers.ts, 35, 51)) + +var b04: Pick; +>b04 : Symbol(b04, Decl(mappedTypeModifiers.ts, 63, 3), Decl(mappedTypeModifiers.ts, 64, 3), Decl(mappedTypeModifiers.ts, 65, 3), Decl(mappedTypeModifiers.ts, 66, 3), Decl(mappedTypeModifiers.ts, 67, 3), Decl(mappedTypeModifiers.ts, 68, 3), Decl(mappedTypeModifiers.ts, 69, 3)) >Pick : Symbol(Pick, Decl(lib.d.ts, --, --)) ->Partial : Symbol(Partial, Decl(lib.d.ts, --, --)) ->B : Symbol(B, Decl(mappedTypeModifiers.ts, 42, 51)) ->B : Symbol(B, Decl(mappedTypeModifiers.ts, 42, 51)) - -var b02: Pick>, keyof B>; ->b02 : Symbol(b02, Decl(mappedTypeModifiers.ts, 64, 3), Decl(mappedTypeModifiers.ts, 65, 3), Decl(mappedTypeModifiers.ts, 66, 3), Decl(mappedTypeModifiers.ts, 67, 3), Decl(mappedTypeModifiers.ts, 68, 3)) ->Pick : Symbol(Pick, Decl(lib.d.ts, --, --)) ->Partial : Symbol(Partial, Decl(lib.d.ts, --, --)) ->Readonly : Symbol(Readonly, Decl(lib.d.ts, --, --)) ->B : Symbol(B, Decl(mappedTypeModifiers.ts, 42, 51)) ->B : Symbol(B, Decl(mappedTypeModifiers.ts, 42, 51)) - -// Validate that isomorphic mapped types preserve optional modifier -var b03: BP; ->b03 : Symbol(b03, Decl(mappedTypeModifiers.ts, 71, 3), Decl(mappedTypeModifiers.ts, 72, 3)) ->BP : Symbol(BP, Decl(mappedTypeModifiers.ts, 45, 73)) - -var b03: Partial; ->b03 : Symbol(b03, Decl(mappedTypeModifiers.ts, 71, 3), Decl(mappedTypeModifiers.ts, 72, 3)) ->Partial : Symbol(Partial, Decl(lib.d.ts, --, --)) ->B : Symbol(B, Decl(mappedTypeModifiers.ts, 42, 51)) - -// Validate that isomorphic mapped types preserve readonly modifier -var b04: BR; ->b04 : Symbol(b04, Decl(mappedTypeModifiers.ts, 75, 3), Decl(mappedTypeModifiers.ts, 76, 3)) ->BR : Symbol(BR, Decl(mappedTypeModifiers.ts, 46, 51)) - -var b04: Readonly; ->b04 : Symbol(b04, Decl(mappedTypeModifiers.ts, 75, 3), Decl(mappedTypeModifiers.ts, 76, 3)) ->Readonly : Symbol(Readonly, Decl(lib.d.ts, --, --)) ->B : Symbol(B, Decl(mappedTypeModifiers.ts, 42, 51)) - -// Validate that isomorphic mapped types preserve both partial and readonly modifiers -var b05: BPR; ->b05 : Symbol(b05, Decl(mappedTypeModifiers.ts, 79, 3), Decl(mappedTypeModifiers.ts, 80, 3), Decl(mappedTypeModifiers.ts, 81, 3), Decl(mappedTypeModifiers.ts, 82, 3), Decl(mappedTypeModifiers.ts, 83, 3)) ->BPR : Symbol(BPR, Decl(mappedTypeModifiers.ts, 47, 67)) - -var b05: Partial
; ->b05 : Symbol(b05, Decl(mappedTypeModifiers.ts, 79, 3), Decl(mappedTypeModifiers.ts, 80, 3), Decl(mappedTypeModifiers.ts, 81, 3), Decl(mappedTypeModifiers.ts, 82, 3), Decl(mappedTypeModifiers.ts, 83, 3)) ->Partial : Symbol(Partial, Decl(lib.d.ts, --, --)) ->BR : Symbol(BR, Decl(mappedTypeModifiers.ts, 46, 51)) - -var b05: Readonly; ->b05 : Symbol(b05, Decl(mappedTypeModifiers.ts, 79, 3), Decl(mappedTypeModifiers.ts, 80, 3), Decl(mappedTypeModifiers.ts, 81, 3), Decl(mappedTypeModifiers.ts, 82, 3), Decl(mappedTypeModifiers.ts, 83, 3)) ->Readonly : Symbol(Readonly, Decl(lib.d.ts, --, --)) ->BP : Symbol(BP, Decl(mappedTypeModifiers.ts, 45, 73)) - -var b05: Partial>; ->b05 : Symbol(b05, Decl(mappedTypeModifiers.ts, 79, 3), Decl(mappedTypeModifiers.ts, 80, 3), Decl(mappedTypeModifiers.ts, 81, 3), Decl(mappedTypeModifiers.ts, 82, 3), Decl(mappedTypeModifiers.ts, 83, 3)) ->Partial : Symbol(Partial, Decl(lib.d.ts, --, --)) ->Readonly : Symbol(Readonly, Decl(lib.d.ts, --, --)) ->B : Symbol(B, Decl(mappedTypeModifiers.ts, 42, 51)) - -var b05: Readonly>; ->b05 : Symbol(b05, Decl(mappedTypeModifiers.ts, 79, 3), Decl(mappedTypeModifiers.ts, 80, 3), Decl(mappedTypeModifiers.ts, 81, 3), Decl(mappedTypeModifiers.ts, 82, 3), Decl(mappedTypeModifiers.ts, 83, 3)) ->Readonly : Symbol(Readonly, Decl(lib.d.ts, --, --)) ->Partial : Symbol(Partial, Decl(lib.d.ts, --, --)) ->B : Symbol(B, Decl(mappedTypeModifiers.ts, 42, 51)) +>BPR : Symbol(BPR, Decl(mappedTypeModifiers.ts, 39, 67)) +>B : Symbol(B, Decl(mappedTypeModifiers.ts, 35, 51)) diff --git a/tests/baselines/reference/mappedTypeModifiers.types b/tests/baselines/reference/mappedTypeModifiers.types index 61b9bfc03b2..befda7e371e 100644 --- a/tests/baselines/reference/mappedTypeModifiers.types +++ b/tests/baselines/reference/mappedTypeModifiers.types @@ -5,11 +5,6 @@ type T = { a: number, b: string }; >a : number >b : string -type TU = { a: number | undefined, b: string | undefined }; ->TU : TU ->a : number | undefined ->b : string | undefined - type TP = { a?: number, b?: string }; >TP : TP >a : number | undefined @@ -25,7 +20,6 @@ type TPR = { readonly a?: number, readonly b?: string }; >a : number | undefined >b : string | undefined -// Validate they all have the same keys var v00: "a" | "b"; >v00 : "a" | "b" @@ -33,10 +27,6 @@ var v00: keyof T; >v00 : "a" | "b" >T : T -var v00: keyof TU; ->v00 : "a" | "b" ->TU : TU - var v00: keyof TP; >v00 : "a" | "b" >TP : TP @@ -49,103 +39,114 @@ var v00: keyof TPR; >v00 : "a" | "b" >TPR : TPR -// Validate that non-isomorphic mapped types strip modifiers var v01: T; >v01 : T >T : T -var v01: Pick; +var v01: { [P in keyof T]: T[P] }; >v01 : T ->Pick : Pick ->TR : TR +>P : P >T : T +>T : T +>P : P -var v01: Pick, keyof T>; +var v01: Pick; >v01 : T >Pick : Pick ->Readonly : Readonly >T : T >T : T -// Validate that non-isomorphic mapped types strip modifiers -var v02: TU; ->v02 : TU ->TU : TU +var v01: Pick, keyof T>; +>v01 : T +>Pick : Pick +>Pick : Pick +>T : T +>T : T +>T : T + +var v02: TP; +>v02 : TP +>TP : TP + +var v02: { [P in keyof T]?: T[P] }; +>v02 : TP +>P : P +>T : T +>T : T +>P : P + +var v02: Partial; +>v02 : TP +>Partial : Partial +>T : T var v02: Pick; ->v02 : TU +>v02 : TP >Pick : Pick >TP : TP >T : T -var v02: Pick; ->v02 : TU ->Pick : Pick ->TPR : TPR ->T : T - -var v02: Pick, keyof T>; ->v02 : TU ->Pick : Pick ->Partial : Partial ->T : T ->T : T - -var v02: Pick>, keyof T>; ->v02 : TU ->Pick : Pick ->Partial : Partial ->Readonly : Readonly ->T : T ->T : T - -// Validate that isomorphic mapped types preserve optional modifier -var v03: TP; ->v03 : TP ->TP : TP - -var v03: Partial; ->v03 : TP ->Partial : Partial ->T : T - -// Validate that isomorphic mapped types preserve readonly modifier -var v04: TR; ->v04 : TR +var v03: TR; +>v03 : TR >TR : TR -var v04: Readonly; ->v04 : TR +var v03: { readonly [P in keyof T]: T[P] }; +>v03 : TR +>P : P +>T : T +>T : T +>P : P + +var v03: Readonly; +>v03 : TR >Readonly : Readonly >T : T -// Validate that isomorphic mapped types preserve both partial and readonly modifiers -var v05: TPR; ->v05 : TPR +var v03: Pick; +>v03 : TR +>Pick : Pick +>TR : TR +>T : T + +var v04: TPR; +>v04 : TPR >TPR : TPR -var v05: Partial; ->v05 : TPR +var v04: { readonly [P in keyof T]?: T[P] }; +>v04 : TPR +>P : P +>T : T +>T : T +>P : P + +var v04: Partial; +>v04 : TPR >Partial : Partial >TR : TR -var v05: Readonly; ->v05 : TPR +var v04: Readonly; +>v04 : TPR >Readonly : Readonly >TP : TP -var v05: Partial>; ->v05 : TPR +var v04: Partial>; +>v04 : TPR >Partial : Partial >Readonly : Readonly >T : T -var v05: Readonly>; ->v05 : TPR +var v04: Readonly>; +>v04 : TPR >Readonly : Readonly >Partial : Partial >T : T +var v04: Pick; +>v04 : TPR +>Pick : Pick +>TPR : TPR +>T : T + type Boxified = { [P in keyof T]: { x: T[P] } }; >Boxified : Boxified >T : T @@ -162,13 +163,6 @@ type B = { a: { x: number }, b: { x: string } }; >b : { x: string; } >x : string -type BU = { a: { x: number } | undefined, b: { x: string } | undefined }; ->BU : BU ->a : { x: number; } | undefined ->x : number ->b : { x: string; } | undefined ->x : string - type BP = { a?: { x: number }, b?: { x: string } }; >BP : BP >a : { x: number; } | undefined @@ -190,7 +184,6 @@ type BPR = { readonly a?: { x: number }, readonly b?: { x: string } }; >b : { x: string; } | undefined >x : string -// Validate they all have the same keys var b00: "a" | "b"; >b00 : "a" | "b" @@ -198,10 +191,6 @@ var b00: keyof B; >b00 : "a" | "b" >B : B -var b00: keyof BU; ->b00 : "a" | "b" ->BU : BU - var b00: keyof BP; >b00 : "a" | "b" >BP : BP @@ -214,100 +203,111 @@ var b00: keyof BPR; >b00 : "a" | "b" >BPR : BPR -// Validate that non-isomorphic mapped types strip modifiers var b01: B; >b01 : B >B : B -var b01: Pick; +var b01: { [P in keyof B]: B[P] }; +>b01 : B +>P : P +>B : B +>B : B +>P : P + +var b01: Pick; >b01 : B >Pick : Pick ->BR : BR +>B : B >B : B -var b01: Pick, keyof B>; +var b01: Pick, keyof B>; >b01 : B >Pick : Pick ->Readonly : Readonly ->BR : BR +>Pick : Pick +>B : B +>B : B >B : B -// Validate that non-isomorphic mapped types strip modifiers -var b02: BU; ->b02 : BU ->BU : BU +var b02: BP; +>b02 : BP +>BP : BP + +var b02: { [P in keyof B]?: B[P] }; +>b02 : BP +>P : P +>B : B +>B : B +>P : P + +var b02: Partial; +>b02 : BP +>Partial : Partial +>B : B var b02: Pick; ->b02 : BU +>b02 : BP >Pick : Pick >BP : BP >B : B -var b02: Pick; ->b02 : BU +var b03: BR; +>b03 : BR +>BR : BR + +var b03: { readonly [P in keyof B]: B[P] }; +>b03 : BR +>P : P +>B : B +>B : B +>P : P + +var b03: Readonly; +>b03 : BR +>Readonly : Readonly +>B : B + +var b03: Pick; +>b03 : BR +>Pick : Pick +>BR : BR +>B : B + +var b04: BPR; +>b04 : BPR +>BPR : BPR + +var b04: { readonly [P in keyof B]?: B[P] }; +>b04 : BPR +>P : P +>B : B +>B : B +>P : P + +var b04: Partial
; +>b04 : BPR +>Partial : Partial +>BR : BR + +var b04: Readonly; +>b04 : BPR +>Readonly : Readonly +>BP : BP + +var b04: Partial>; +>b04 : BPR +>Partial : Partial +>Readonly : Readonly +>B : B + +var b04: Readonly>; +>b04 : BPR +>Readonly : Readonly +>Partial : Partial +>B : B + +var b04: Pick; +>b04 : BPR >Pick : Pick >BPR : BPR >B : B -var b02: Pick, keyof B>; ->b02 : BU ->Pick : Pick ->Partial : Partial ->B : B ->B : B - -var b02: Pick>, keyof B>; ->b02 : BU ->Pick : Pick ->Partial : Partial ->Readonly : Readonly ->B : B ->B : B - -// Validate that isomorphic mapped types preserve optional modifier -var b03: BP; ->b03 : BP ->BP : BP - -var b03: Partial; ->b03 : BP ->Partial : Partial ->B : B - -// Validate that isomorphic mapped types preserve readonly modifier -var b04: BR; ->b04 : BR ->BR : BR - -var b04: Readonly; ->b04 : BR ->Readonly : Readonly ->B : B - -// Validate that isomorphic mapped types preserve both partial and readonly modifiers -var b05: BPR; ->b05 : BPR ->BPR : BPR - -var b05: Partial
; ->b05 : BPR ->Partial : Partial ->BR : BR - -var b05: Readonly; ->b05 : BPR ->Readonly : Readonly ->BP : BP - -var b05: Partial>; ->b05 : BPR ->Partial : Partial ->Readonly : Readonly ->B : B - -var b05: Readonly>; ->b05 : BPR ->Readonly : Readonly ->Partial : Partial ->B : B - diff --git a/tests/baselines/reference/subSubClassCanAccessProtectedConstructor.js b/tests/baselines/reference/subSubClassCanAccessProtectedConstructor.js new file mode 100644 index 00000000000..15d6fc70da5 --- /dev/null +++ b/tests/baselines/reference/subSubClassCanAccessProtectedConstructor.js @@ -0,0 +1,51 @@ +//// [subSubClassCanAccessProtectedConstructor.ts] +class Base { + protected constructor() { } + public instance1 = new Base(); // allowed +} + +class Subclass extends Base { + public instance1_1 = new Base(); // allowed + public instance1_2 = new Subclass(); // allowed +} + +class SubclassOfSubclass extends Subclass { + public instance2_1 = new Base(); // allowed + public instance2_2 = new Subclass(); // allowed + public instance2_3 = new SubclassOfSubclass(); // allowed +} + + +//// [subSubClassCanAccessProtectedConstructor.js] +var __extends = (this && this.__extends) || function (d, b) { + for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; + function __() { this.constructor = d; } + d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); +}; +var Base = (function () { + function Base() { + this.instance1 = new Base(); // allowed + } + return Base; +}()); +var Subclass = (function (_super) { + __extends(Subclass, _super); + function Subclass() { + var _this = _super.apply(this, arguments) || this; + _this.instance1_1 = new Base(); // allowed + _this.instance1_2 = new Subclass(); // allowed + return _this; + } + return Subclass; +}(Base)); +var SubclassOfSubclass = (function (_super) { + __extends(SubclassOfSubclass, _super); + function SubclassOfSubclass() { + var _this = _super.apply(this, arguments) || this; + _this.instance2_1 = new Base(); // allowed + _this.instance2_2 = new Subclass(); // allowed + _this.instance2_3 = new SubclassOfSubclass(); // allowed + return _this; + } + return SubclassOfSubclass; +}(Subclass)); diff --git a/tests/baselines/reference/subSubClassCanAccessProtectedConstructor.symbols b/tests/baselines/reference/subSubClassCanAccessProtectedConstructor.symbols new file mode 100644 index 00000000000..8a09e1d742f --- /dev/null +++ b/tests/baselines/reference/subSubClassCanAccessProtectedConstructor.symbols @@ -0,0 +1,40 @@ +=== tests/cases/compiler/subSubClassCanAccessProtectedConstructor.ts === +class Base { +>Base : Symbol(Base, Decl(subSubClassCanAccessProtectedConstructor.ts, 0, 0)) + + protected constructor() { } + public instance1 = new Base(); // allowed +>instance1 : Symbol(Base.instance1, Decl(subSubClassCanAccessProtectedConstructor.ts, 1, 31)) +>Base : Symbol(Base, Decl(subSubClassCanAccessProtectedConstructor.ts, 0, 0)) +} + +class Subclass extends Base { +>Subclass : Symbol(Subclass, Decl(subSubClassCanAccessProtectedConstructor.ts, 3, 1)) +>Base : Symbol(Base, Decl(subSubClassCanAccessProtectedConstructor.ts, 0, 0)) + + public instance1_1 = new Base(); // allowed +>instance1_1 : Symbol(Subclass.instance1_1, Decl(subSubClassCanAccessProtectedConstructor.ts, 5, 29)) +>Base : Symbol(Base, Decl(subSubClassCanAccessProtectedConstructor.ts, 0, 0)) + + public instance1_2 = new Subclass(); // allowed +>instance1_2 : Symbol(Subclass.instance1_2, Decl(subSubClassCanAccessProtectedConstructor.ts, 6, 36)) +>Subclass : Symbol(Subclass, Decl(subSubClassCanAccessProtectedConstructor.ts, 3, 1)) +} + +class SubclassOfSubclass extends Subclass { +>SubclassOfSubclass : Symbol(SubclassOfSubclass, Decl(subSubClassCanAccessProtectedConstructor.ts, 8, 1)) +>Subclass : Symbol(Subclass, Decl(subSubClassCanAccessProtectedConstructor.ts, 3, 1)) + + public instance2_1 = new Base(); // allowed +>instance2_1 : Symbol(SubclassOfSubclass.instance2_1, Decl(subSubClassCanAccessProtectedConstructor.ts, 10, 43)) +>Base : Symbol(Base, Decl(subSubClassCanAccessProtectedConstructor.ts, 0, 0)) + + public instance2_2 = new Subclass(); // allowed +>instance2_2 : Symbol(SubclassOfSubclass.instance2_2, Decl(subSubClassCanAccessProtectedConstructor.ts, 11, 36)) +>Subclass : Symbol(Subclass, Decl(subSubClassCanAccessProtectedConstructor.ts, 3, 1)) + + public instance2_3 = new SubclassOfSubclass(); // allowed +>instance2_3 : Symbol(SubclassOfSubclass.instance2_3, Decl(subSubClassCanAccessProtectedConstructor.ts, 12, 40)) +>SubclassOfSubclass : Symbol(SubclassOfSubclass, Decl(subSubClassCanAccessProtectedConstructor.ts, 8, 1)) +} + diff --git a/tests/baselines/reference/subSubClassCanAccessProtectedConstructor.types b/tests/baselines/reference/subSubClassCanAccessProtectedConstructor.types new file mode 100644 index 00000000000..253f6221c78 --- /dev/null +++ b/tests/baselines/reference/subSubClassCanAccessProtectedConstructor.types @@ -0,0 +1,46 @@ +=== tests/cases/compiler/subSubClassCanAccessProtectedConstructor.ts === +class Base { +>Base : Base + + protected constructor() { } + public instance1 = new Base(); // allowed +>instance1 : Base +>new Base() : Base +>Base : typeof Base +} + +class Subclass extends Base { +>Subclass : Subclass +>Base : Base + + public instance1_1 = new Base(); // allowed +>instance1_1 : Base +>new Base() : Base +>Base : typeof Base + + public instance1_2 = new Subclass(); // allowed +>instance1_2 : Subclass +>new Subclass() : Subclass +>Subclass : typeof Subclass +} + +class SubclassOfSubclass extends Subclass { +>SubclassOfSubclass : SubclassOfSubclass +>Subclass : Subclass + + public instance2_1 = new Base(); // allowed +>instance2_1 : Base +>new Base() : Base +>Base : typeof Base + + public instance2_2 = new Subclass(); // allowed +>instance2_2 : Subclass +>new Subclass() : Subclass +>Subclass : typeof Subclass + + public instance2_3 = new SubclassOfSubclass(); // allowed +>instance2_3 : SubclassOfSubclass +>new SubclassOfSubclass() : SubclassOfSubclass +>SubclassOfSubclass : typeof SubclassOfSubclass +} + diff --git a/tests/baselines/reference/unusedLocalsAndObjectSpread.errors.txt b/tests/baselines/reference/unusedLocalsAndObjectSpread.errors.txt new file mode 100644 index 00000000000..56f2ba927fb --- /dev/null +++ b/tests/baselines/reference/unusedLocalsAndObjectSpread.errors.txt @@ -0,0 +1,40 @@ +tests/cases/compiler/unusedLocalsAndObjectSpread.ts(21,18): error TS6133: 'bar' is declared but never used. +tests/cases/compiler/unusedLocalsAndObjectSpread.ts(28,21): error TS6133: 'bar' is declared but never used. + + +==== tests/cases/compiler/unusedLocalsAndObjectSpread.ts (2 errors) ==== + + declare var console: { log(a: any): void }; + + function one() { + const foo = { a: 1, b: 2 }; + // 'a' is declared but never used + const {a, ...bar} = foo; + console.log(bar); + } + + function two() { + const foo = { a: 1, b: 2 }; + // '_' is declared but never used + const {a: _, ...bar} = foo; + console.log(bar); + } + + function three() { + const foo = { a: 1, b: 2 }; + // 'a' is declared but never used + const {a, ...bar} = foo; // bar should be unused + ~~~ +!!! error TS6133: 'bar' is declared but never used. + //console.log(bar); + } + + function four() { + const foo = { a: 1, b: 2 }; + // '_' is declared but never used + const {a: _, ...bar} = foo; // bar should be unused + ~~~ +!!! error TS6133: 'bar' is declared but never used. + //console.log(bar); + } + \ No newline at end of file diff --git a/tests/baselines/reference/unusedLocalsAndObjectSpread.js b/tests/baselines/reference/unusedLocalsAndObjectSpread.js new file mode 100644 index 00000000000..2878f1b5c5c --- /dev/null +++ b/tests/baselines/reference/unusedLocalsAndObjectSpread.js @@ -0,0 +1,67 @@ +//// [unusedLocalsAndObjectSpread.ts] + +declare var console: { log(a: any): void }; + +function one() { + const foo = { a: 1, b: 2 }; + // 'a' is declared but never used + const {a, ...bar} = foo; + console.log(bar); +} + +function two() { + const foo = { a: 1, b: 2 }; + // '_' is declared but never used + const {a: _, ...bar} = foo; + console.log(bar); +} + +function three() { + const foo = { a: 1, b: 2 }; + // 'a' is declared but never used + const {a, ...bar} = foo; // bar should be unused + //console.log(bar); +} + +function four() { + const foo = { a: 1, b: 2 }; + // '_' is declared but never used + const {a: _, ...bar} = foo; // bar should be unused + //console.log(bar); +} + + +//// [unusedLocalsAndObjectSpread.js] +var __rest = (this && this.__rest) || function (s, e) { + var t = {}; + for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0) + t[p] = s[p]; + if (s != null && typeof Object.getOwnPropertySymbols === "function") + for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) if (e.indexOf(p[i]) < 0) + t[p[i]] = s[p[i]]; + return t; +}; +function one() { + var foo = { a: 1, b: 2 }; + // 'a' is declared but never used + var a = foo.a, bar = __rest(foo, ["a"]); + console.log(bar); +} +function two() { + var foo = { a: 1, b: 2 }; + // '_' is declared but never used + var _ = foo.a, bar = __rest(foo, ["a"]); + console.log(bar); +} +function three() { + var foo = { a: 1, b: 2 }; + // 'a' is declared but never used + var a = foo.a, bar = __rest(foo, ["a"]); // bar should be unused + //console.log(bar); +} +function four() { + var foo = { a: 1, b: 2 }; + // '_' is declared but never used + var _ = foo.a, bar = __rest(foo, ["a"]); // bar should be unused + //console.log(bar); +} diff --git a/tests/cases/compiler/subSubClassCanAccessProtectedConstructor.ts b/tests/cases/compiler/subSubClassCanAccessProtectedConstructor.ts new file mode 100644 index 00000000000..fc5e9794500 --- /dev/null +++ b/tests/cases/compiler/subSubClassCanAccessProtectedConstructor.ts @@ -0,0 +1,15 @@ +class Base { + protected constructor() { } + public instance1 = new Base(); // allowed +} + +class Subclass extends Base { + public instance1_1 = new Base(); // allowed + public instance1_2 = new Subclass(); // allowed +} + +class SubclassOfSubclass extends Subclass { + public instance2_1 = new Base(); // allowed + public instance2_2 = new Subclass(); // allowed + public instance2_3 = new SubclassOfSubclass(); // allowed +} diff --git a/tests/cases/compiler/unusedLocalsAndObjectSpread.ts b/tests/cases/compiler/unusedLocalsAndObjectSpread.ts new file mode 100644 index 00000000000..b042b412c8e --- /dev/null +++ b/tests/cases/compiler/unusedLocalsAndObjectSpread.ts @@ -0,0 +1,31 @@ +//@noUnusedLocals:true + +declare var console: { log(a: any): void }; + +function one() { + const foo = { a: 1, b: 2 }; + // 'a' is declared but never used + const {a, ...bar} = foo; + console.log(bar); +} + +function two() { + const foo = { a: 1, b: 2 }; + // '_' is declared but never used + const {a: _, ...bar} = foo; + console.log(bar); +} + +function three() { + const foo = { a: 1, b: 2 }; + // 'a' is declared but never used + const {a, ...bar} = foo; // bar should be unused + //console.log(bar); +} + +function four() { + const foo = { a: 1, b: 2 }; + // '_' is declared but never used + const {a: _, ...bar} = foo; // bar should be unused + //console.log(bar); +} diff --git a/tests/cases/conformance/types/keyof/circularIndexedAccessErrors.ts b/tests/cases/conformance/types/keyof/circularIndexedAccessErrors.ts new file mode 100644 index 00000000000..c01030c7fa9 --- /dev/null +++ b/tests/cases/conformance/types/keyof/circularIndexedAccessErrors.ts @@ -0,0 +1,31 @@ +// @declaration: true + +type T1 = { + x: T1["x"]; // Error +}; + +type T2 = { + x: T2[K]; // Error + y: number; +} + +declare let x2: T2<"x">; +let x2x = x2.x; + +interface T3> { + x: T["x"]; // Error +} + +interface T4> { + x: T4["x"]; // Error +} + +class C1 { + x: C1["x"]; // Error +} + +class C2 { + x: this["y"]; // Error + y: this["z"]; // Error + z: this["x"]; // Error +} \ No newline at end of file diff --git a/tests/cases/conformance/types/keyof/keyofAndIndexedAccess.ts b/tests/cases/conformance/types/keyof/keyofAndIndexedAccess.ts index 08bcfb28204..ea6a3c2358a 100644 --- a/tests/cases/conformance/types/keyof/keyofAndIndexedAccess.ts +++ b/tests/cases/conformance/types/keyof/keyofAndIndexedAccess.ts @@ -250,6 +250,53 @@ function f74(func: (x: T, y: U, k: K) => (T | U)[ let b = func({ a: 1, b: "hello" }, { a: 2, b: true }, 'b'); // string | boolean } +function f80(obj: T) { + let a1 = obj.a; // { x: any } + let a2 = obj['a']; // { x: any } + let a3 = obj['a'] as T['a']; // T["a"] + let x1 = obj.a.x; // any + let x2 = obj['a']['x']; // any + let x3 = obj['a']['x'] as T['a']['x']; // T["a"]["x"] +} + +function f81(obj: T) { + return obj['a']['x'] as T['a']['x']; +} + +function f82() { + let x1 = f81({ a: { x: "hello" } }); // string + let x2 = f81({ a: { x: 42 } }); // number +} + +function f83(obj: T, key: K) { + return obj[key]['x'] as T[K]['x']; +} + +function f84() { + let x1 = f83({ foo: { x: "hello" } }, "foo"); // string + let x2 = f83({ bar: { x: 42 } }, "bar"); // number +} + +class C1 { + x: number; + get(key: K) { + return this[key]; + } + set(key: K, value: this[K]) { + this[key] = value; + } + foo() { + let x1 = this.x; // number + let x2 = this["x"]; // number + let x3 = this.get("x"); // this["x"] + let x4 = getProperty(this, "x"); // this["x"] + this.x = 42; + this["x"] = 42; + this.set("x", 42); + setProperty(this, "x", 42); + } +} + // Repros from #12011 class Base { @@ -365,4 +412,22 @@ interface R { function f(p: K) { let a: any; a[p].add; // any -} \ No newline at end of file +} + +// Repro from #12651 + +type MethodDescriptor = { + name: string; + args: any[]; + returnValue: any; +} + +declare function dispatchMethod(name: M['name'], args: M['args']): M['returnValue']; + +type SomeMethodDescriptor = { + name: "someMethod"; + args: [string, number]; + returnValue: string[]; +} + +let result = dispatchMethod("someMethod", ["hello", 35]); \ No newline at end of file diff --git a/tests/cases/conformance/types/mapped/mappedTypeErrors.ts b/tests/cases/conformance/types/mapped/mappedTypeErrors.ts index a198d4e0dc1..4be6b6b098d 100644 --- a/tests/cases/conformance/types/mapped/mappedTypeErrors.ts +++ b/tests/cases/conformance/types/mapped/mappedTypeErrors.ts @@ -84,4 +84,44 @@ function f21() { let x1 = objAndPartial({ x: 0, y: 0 }, { x: 1 }); let x2 = objAndPartial({ x: 0, y: 0 }, { x: 1, y: 1 }); let x3 = objAndPartial({ x: 0, y: 0 }, { x: 1, y: 1, z: 1 }); // Error -} \ No newline at end of file +} + +// Verify use of Pick for setState functions (#12793) + +interface Foo { + a: string; + b?: number; +} + +function setState(obj: T, props: Pick) { + for (let k in props) { + obj[k] = props[k]; + } +} + +let foo: Foo = { a: "hello", b: 42 }; +setState(foo, { a: "test", b: 43 }) +setState(foo, { a: "hi" }); +setState(foo, { b: undefined }); +setState(foo, { }); +setState(foo, foo); +setState(foo, { a: undefined }); // Error +setState(foo, { c: true }); // Error + +class C { + state: T; + setState(props: Pick) { + for (let k in props) { + this.state[k] = props[k]; + } + } +} + +let c = new C(); +c.setState({ a: "test", b: 43 }); +c.setState({ a: "hi" }); +c.setState({ b: undefined }); +c.setState({ }); +c.setState(foo); +c.setState({ a: undefined }); // Error +c.setState({ c: true }); // Error diff --git a/tests/cases/conformance/types/mapped/mappedTypeModifiers.ts b/tests/cases/conformance/types/mapped/mappedTypeModifiers.ts index 1e76c5b7452..30aa652f0d9 100644 --- a/tests/cases/conformance/types/mapped/mappedTypeModifiers.ts +++ b/tests/cases/conformance/types/mapped/mappedTypeModifiers.ts @@ -1,85 +1,71 @@ // @strictNullChecks: true type T = { a: number, b: string }; -type TU = { a: number | undefined, b: string | undefined }; type TP = { a?: number, b?: string }; type TR = { readonly a: number, readonly b: string }; type TPR = { readonly a?: number, readonly b?: string }; -// Validate they all have the same keys var v00: "a" | "b"; var v00: keyof T; -var v00: keyof TU; var v00: keyof TP; var v00: keyof TR; var v00: keyof TPR; -// Validate that non-isomorphic mapped types strip modifiers var v01: T; -var v01: Pick; -var v01: Pick, keyof T>; +var v01: { [P in keyof T]: T[P] }; +var v01: Pick; +var v01: Pick, keyof T>; -// Validate that non-isomorphic mapped types strip modifiers -var v02: TU; +var v02: TP; +var v02: { [P in keyof T]?: T[P] }; +var v02: Partial; var v02: Pick; -var v02: Pick; -var v02: Pick, keyof T>; -var v02: Pick>, keyof T>; -// Validate that isomorphic mapped types preserve optional modifier -var v03: TP; -var v03: Partial; +var v03: TR; +var v03: { readonly [P in keyof T]: T[P] }; +var v03: Readonly; +var v03: Pick; -// Validate that isomorphic mapped types preserve readonly modifier -var v04: TR; -var v04: Readonly; - -// Validate that isomorphic mapped types preserve both partial and readonly modifiers -var v05: TPR; -var v05: Partial; -var v05: Readonly; -var v05: Partial>; -var v05: Readonly>; +var v04: TPR; +var v04: { readonly [P in keyof T]?: T[P] }; +var v04: Partial; +var v04: Readonly; +var v04: Partial>; +var v04: Readonly>; +var v04: Pick; type Boxified = { [P in keyof T]: { x: T[P] } }; type B = { a: { x: number }, b: { x: string } }; -type BU = { a: { x: number } | undefined, b: { x: string } | undefined }; type BP = { a?: { x: number }, b?: { x: string } }; type BR = { readonly a: { x: number }, readonly b: { x: string } }; type BPR = { readonly a?: { x: number }, readonly b?: { x: string } }; -// Validate they all have the same keys var b00: "a" | "b"; var b00: keyof B; -var b00: keyof BU; var b00: keyof BP; var b00: keyof BR; var b00: keyof BPR; -// Validate that non-isomorphic mapped types strip modifiers var b01: B; -var b01: Pick; -var b01: Pick, keyof B>; +var b01: { [P in keyof B]: B[P] }; +var b01: Pick; +var b01: Pick, keyof B>; -// Validate that non-isomorphic mapped types strip modifiers -var b02: BU; +var b02: BP; +var b02: { [P in keyof B]?: B[P] }; +var b02: Partial; var b02: Pick; -var b02: Pick; -var b02: Pick, keyof B>; -var b02: Pick>, keyof B>; -// Validate that isomorphic mapped types preserve optional modifier -var b03: BP; -var b03: Partial; +var b03: BR; +var b03: { readonly [P in keyof B]: B[P] }; +var b03: Readonly; +var b03: Pick; -// Validate that isomorphic mapped types preserve readonly modifier -var b04: BR; -var b04: Readonly; - -// Validate that isomorphic mapped types preserve both partial and readonly modifiers -var b05: BPR; -var b05: Partial
; -var b05: Readonly; -var b05: Partial>; -var b05: Readonly>; \ No newline at end of file +var b04: BPR; +var b04: { readonly [P in keyof B]?: B[P] }; +var b04: Partial
; +var b04: Readonly; +var b04: Partial>; +var b04: Readonly>; +var b04: Pick; \ No newline at end of file diff --git a/tests/cases/fourslash/commentBraceCompletionPosition.ts b/tests/cases/fourslash/commentBraceCompletionPosition.ts index b92c49d3a14..3730a3466c9 100644 --- a/tests/cases/fourslash/commentBraceCompletionPosition.ts +++ b/tests/cases/fourslash/commentBraceCompletionPosition.ts @@ -14,10 +14,10 @@ //// } goTo.marker('1'); -verify.not.isValidBraceCompletionAtPosition('('); +verify.isValidBraceCompletionAtPosition('('); goTo.marker('2'); -verify.not.isValidBraceCompletionAtPosition('('); +verify.isValidBraceCompletionAtPosition('('); goTo.marker('3'); -verify.not.isValidBraceCompletionAtPosition('('); \ No newline at end of file +verify.isValidBraceCompletionAtPosition('('); \ No newline at end of file