From 143fc9164f0466618910da58827f20f8b126dccc Mon Sep 17 00:00:00 2001 From: Mohamed Hegazy Date: Mon, 28 Nov 2016 17:30:26 -0800 Subject: [PATCH 1/8] Revert https://github.com/Microsoft/TypeScript/pull/12207 --- src/lib/es2017.object.d.ts | 2 +- .../useObjectValuesAndEntries1.types | 30 +++++++++---------- .../useObjectValuesAndEntries4.types | 8 ++--- 3 files changed, 20 insertions(+), 20 deletions(-) diff --git a/src/lib/es2017.object.d.ts b/src/lib/es2017.object.d.ts index c219f467ac985..c15e21364d2d9 100644 --- a/src/lib/es2017.object.d.ts +++ b/src/lib/es2017.object.d.ts @@ -9,6 +9,6 @@ interface ObjectConstructor { * Returns an array of key/values of the enumerable properties of an object * @param o Object that contains the properties and methods. This can be an object that you created or an existing Document Object Model (DOM) object. */ - entries(o: T): [keyof T, T[K]][]; + entries(o: { [s: string]: T }): [string, T][]; entries(o: any): [string, any][]; } diff --git a/tests/baselines/reference/useObjectValuesAndEntries1.types b/tests/baselines/reference/useObjectValuesAndEntries1.types index f04201450c00f..d9ccc019f759a 100644 --- a/tests/baselines/reference/useObjectValuesAndEntries1.types +++ b/tests/baselines/reference/useObjectValuesAndEntries1.types @@ -22,38 +22,38 @@ for (var x of Object.values(o)) { } var entries = Object.entries(o); // <-- entries: ['a' | 'b', number][] ->entries : ["a" | "b", number][] ->Object.entries(o) : ["a" | "b", number][] ->Object.entries : { (o: T): [keyof T, T[K]][]; (o: any): [string, any][]; } +>entries : [string, number][] +>Object.entries(o) : [string, number][] +>Object.entries : { (o: { [s: string]: T; }): [string, T][]; (o: any): [string, any][]; } >Object : ObjectConstructor ->entries : { (o: T): [keyof T, T[K]][]; (o: any): [string, any][]; } +>entries : { (o: { [s: string]: T; }): [string, T][]; (o: any): [string, any][]; } >o : { a: number; b: number; } var entries1 = Object.entries(1); // <-- entries: [string, any][] >entries1 : [string, any][] >Object.entries(1) : [string, any][] ->Object.entries : { (o: T): [keyof T, T[K]][]; (o: any): [string, any][]; } +>Object.entries : { (o: { [s: string]: T; }): [string, T][]; (o: any): [string, any][]; } >Object : ObjectConstructor ->entries : { (o: T): [keyof T, T[K]][]; (o: any): [string, any][]; } +>entries : { (o: { [s: string]: T; }): [string, T][]; (o: any): [string, any][]; } >1 : 1 var entries2 = Object.entries({a: true, b: 2}) // ['a' | 'b', number | boolean][] ->entries2 : ["a" | "b", number | boolean][] ->Object.entries({a: true, b: 2}) : ["a" | "b", number | boolean][] ->Object.entries : { (o: T): [keyof T, T[K]][]; (o: any): [string, any][]; } +>entries2 : [string, number | boolean][] +>Object.entries({a: true, b: 2}) : [string, number | boolean][] +>Object.entries : { (o: { [s: string]: T; }): [string, T][]; (o: any): [string, any][]; } >Object : ObjectConstructor ->entries : { (o: T): [keyof T, T[K]][]; (o: any): [string, any][]; } ->{a: true, b: 2} : { a: true; b: number; } +>entries : { (o: { [s: string]: T; }): [string, T][]; (o: any): [string, any][]; } +>{a: true, b: 2} : { a: true; b: 2; } >a : boolean >true : true >b : number >2 : 2 var entries3 = Object.entries({}) // [never, any][] ->entries3 : [never, any][] ->Object.entries({}) : [never, any][] ->Object.entries : { (o: T): [keyof T, T[K]][]; (o: any): [string, any][]; } +>entries3 : [string, {}][] +>Object.entries({}) : [string, {}][] +>Object.entries : { (o: { [s: string]: T; }): [string, T][]; (o: any): [string, any][]; } >Object : ObjectConstructor ->entries : { (o: T): [keyof T, T[K]][]; (o: any): [string, any][]; } +>entries : { (o: { [s: string]: T; }): [string, T][]; (o: any): [string, any][]; } >{} : {} diff --git a/tests/baselines/reference/useObjectValuesAndEntries4.types b/tests/baselines/reference/useObjectValuesAndEntries4.types index d68193993e2b6..05af55d42cb6a 100644 --- a/tests/baselines/reference/useObjectValuesAndEntries4.types +++ b/tests/baselines/reference/useObjectValuesAndEntries4.types @@ -22,10 +22,10 @@ for (var x of Object.values(o)) { } var entries = Object.entries(o); ->entries : ["a" | "b", number][] ->Object.entries(o) : ["a" | "b", number][] ->Object.entries : { (o: T): [keyof T, T[K]][]; (o: any): [string, any][]; } +>entries : [string, number][] +>Object.entries(o) : [string, number][] +>Object.entries : { (o: { [s: string]: T; }): [string, T][]; (o: any): [string, any][]; } >Object : ObjectConstructor ->entries : { (o: T): [keyof T, T[K]][]; (o: any): [string, any][]; } +>entries : { (o: { [s: string]: T; }): [string, T][]; (o: any): [string, any][]; } >o : { a: number; b: number; } From 82e84e272e3bda490577b030cf7ced0658f31e72 Mon Sep 17 00:00:00 2001 From: Mohamed Hegazy Date: Mon, 28 Nov 2016 17:30:37 -0800 Subject: [PATCH 2/8] Make sure all overloads have comments --- src/lib/es2017.object.d.ts | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/lib/es2017.object.d.ts b/src/lib/es2017.object.d.ts index c15e21364d2d9..80c2161506a01 100644 --- a/src/lib/es2017.object.d.ts +++ b/src/lib/es2017.object.d.ts @@ -4,11 +4,22 @@ interface ObjectConstructor { * @param o Object that contains the properties and methods. This can be an object that you created or an existing Document Object Model (DOM) object. */ values(o: { [s: string]: T }): T[]; + + /** + * Returns an array of values of the enumerable properties of an object + * @param o Object that contains the properties and methods. This can be an object that you created or an existing Document Object Model (DOM) object. + */ values(o: any): any[]; + /** * Returns an array of key/values of the enumerable properties of an object * @param o Object that contains the properties and methods. This can be an object that you created or an existing Document Object Model (DOM) object. */ entries(o: { [s: string]: T }): [string, T][]; + + /** + * Returns an array of key/values of the enumerable properties of an object + * @param o Object that contains the properties and methods. This can be an object that you created or an existing Document Object Model (DOM) object. + */ entries(o: any): [string, any][]; } From 1418fd170d17692d44370831779934fba7c2665d Mon Sep 17 00:00:00 2001 From: Vladimir Matveev Date: Tue, 29 Nov 2016 10:14:22 -0800 Subject: [PATCH 3/8] send begin/end notifications when installing types packages (#12551) --- .../unittests/tsserverProjectSystem.ts | 3 +- src/harness/unittests/typingsInstaller.ts | 114 ++++++++++++++++-- src/server/protocol.ts | 34 ++++++ src/server/server.ts | 39 +++++- src/server/shared.ts | 3 +- src/server/types.d.ts | 20 ++- .../typingsInstaller/nodeTypingsInstaller.ts | 8 +- .../typingsInstaller/typingsInstaller.ts | 80 ++++++------ 8 files changed, 240 insertions(+), 61 deletions(-) diff --git a/src/harness/unittests/tsserverProjectSystem.ts b/src/harness/unittests/tsserverProjectSystem.ts index a0a6ac7f01e04..368d2a660d4e5 100644 --- a/src/harness/unittests/tsserverProjectSystem.ts +++ b/src/harness/unittests/tsserverProjectSystem.ts @@ -51,9 +51,8 @@ namespace ts.projectSystem { throttleLimit: number, installTypingHost: server.ServerHost, readonly typesRegistry = createMap(), - telemetryEnabled?: boolean, log?: TI.Log) { - super(installTypingHost, globalTypingsCacheLocation, safeList.path, throttleLimit, telemetryEnabled, log); + super(installTypingHost, globalTypingsCacheLocation, safeList.path, throttleLimit, log); } safeFileList = safeList.path; diff --git a/src/harness/unittests/typingsInstaller.ts b/src/harness/unittests/typingsInstaller.ts index aea9f4eb9ed1c..62d2f7ac80146 100644 --- a/src/harness/unittests/typingsInstaller.ts +++ b/src/harness/unittests/typingsInstaller.ts @@ -20,13 +20,12 @@ namespace ts.projectSystem { } class Installer extends TestTypingsInstaller { - constructor(host: server.ServerHost, p?: InstallerParams, telemetryEnabled?: boolean, log?: TI.Log) { + constructor(host: server.ServerHost, p?: InstallerParams, log?: TI.Log) { super( (p && p.globalTypingsCacheLocation) || "/a/data", (p && p.throttleLimit) || 5, host, (p && p.typesRegistry), - telemetryEnabled, log); } @@ -36,7 +35,7 @@ namespace ts.projectSystem { } } - function executeCommand(self: Installer, host: TestServerHost, installedTypings: string[], typingFiles: FileOrFolder[], cb: TI.RequestCompletedAction): void { + function executeCommand(self: Installer, host: TestServerHost, installedTypings: string[] | string, typingFiles: FileOrFolder[], cb: TI.RequestCompletedAction): void { self.addPostExecAction(installedTypings, success => { for (const file of typingFiles) { host.createFileOrFolder(file, /*createParentDirectory*/ true); @@ -907,7 +906,7 @@ namespace ts.projectSystem { const host = createServerHost([f1, packageJson]); const installer = new (class extends Installer { constructor() { - super(host, { globalTypingsCacheLocation: "/tmp" }, /*telemetryEnabled*/ false, { isEnabled: () => true, writeLine: msg => messages.push(msg) }); + super(host, { globalTypingsCacheLocation: "/tmp" }, { isEnabled: () => true, writeLine: msg => messages.push(msg) }); } installWorker(_requestId: number, _args: string[], _cwd: string, _cb: server.typingsInstaller.RequestCompletedAction) { assert(false, "runCommand should not be invoked"); @@ -971,15 +970,18 @@ namespace ts.projectSystem { let seenTelemetryEvent = false; const installer = new (class extends Installer { constructor() { - super(host, { globalTypingsCacheLocation: cachePath, typesRegistry: createTypesRegistry("commander") }, /*telemetryEnabled*/ true); + super(host, { globalTypingsCacheLocation: cachePath, typesRegistry: createTypesRegistry("commander") }); } installWorker(_requestId: number, _args: string[], _cwd: string, cb: server.typingsInstaller.RequestCompletedAction) { const installedTypings = ["@types/commander"]; const typingFiles = [commander]; executeCommand(this, host, installedTypings, typingFiles, cb); } - sendResponse(response: server.SetTypings | server.InvalidateCachedTypings | server.TypingsInstallEvent) { - if (response.kind === server.EventInstall) { + sendResponse(response: server.SetTypings | server.InvalidateCachedTypings | server.BeginInstallTypes | server.EndInstallTypes) { + if (response.kind === server.EventBeginInstallTypes) { + return; + } + if (response.kind === server.EventEndInstallTypes) { assert.deepEqual(response.packagesToInstall, ["@types/commander"]); seenTelemetryEvent = true; return; @@ -997,4 +999,102 @@ namespace ts.projectSystem { checkProjectActualFiles(projectService.inferredProjects[0], [f1.path, commander.path]); }); }); + + describe("progress notifications", () => { + it ("should be sent for success", () => { + const f1 = { + path: "/a/app.js", + content: "" + }; + const package = { + path: "/a/package.json", + content: JSON.stringify({ dependencies: { "commander": "1.0.0" } }) + }; + const cachePath = "/a/cache/"; + const commander = { + path: cachePath + "node_modules/@types/commander/index.d.ts", + content: "export let x: number" + }; + const host = createServerHost([f1, package]); + let beginEvent: server.BeginInstallTypes; + let endEvent: server.EndInstallTypes; + const installer = new (class extends Installer { + constructor() { + super(host, { globalTypingsCacheLocation: cachePath, typesRegistry: createTypesRegistry("commander") }); + } + installWorker(_requestId: number, _args: string[], _cwd: string, cb: server.typingsInstaller.RequestCompletedAction) { + const installedTypings = ["@types/commander"]; + const typingFiles = [commander]; + executeCommand(this, host, installedTypings, typingFiles, cb); + } + sendResponse(response: server.SetTypings | server.InvalidateCachedTypings | server.BeginInstallTypes | server.EndInstallTypes) { + if (response.kind === server.EventBeginInstallTypes) { + beginEvent = response; + return; + } + if (response.kind === server.EventEndInstallTypes) { + endEvent = response; + return; + } + super.sendResponse(response); + } + })(); + const projectService = createProjectService(host, { typingsInstaller: installer }); + projectService.openClientFile(f1.path); + + installer.installAll(/*expectedCount*/ 1); + + assert.isTrue(!!beginEvent); + assert.isTrue(!!endEvent); + assert.isTrue(beginEvent.eventId === endEvent.eventId); + assert.isTrue(endEvent.installSuccess); + checkNumberOfProjects(projectService, { inferredProjects: 1 }); + checkProjectActualFiles(projectService.inferredProjects[0], [f1.path, commander.path]); + }); + + it ("should be sent for error", () => { + const f1 = { + path: "/a/app.js", + content: "" + }; + const package = { + path: "/a/package.json", + content: JSON.stringify({ dependencies: { "commander": "1.0.0" } }) + }; + const cachePath = "/a/cache/"; + const host = createServerHost([f1, package]); + let beginEvent: server.BeginInstallTypes; + let endEvent: server.EndInstallTypes; + const installer = new (class extends Installer { + constructor() { + super(host, { globalTypingsCacheLocation: cachePath, typesRegistry: createTypesRegistry("commander") }); + } + installWorker(_requestId: number, _args: string[], _cwd: string, cb: server.typingsInstaller.RequestCompletedAction) { + executeCommand(this, host, "", [], cb); + } + sendResponse(response: server.SetTypings | server.InvalidateCachedTypings | server.BeginInstallTypes | server.EndInstallTypes) { + if (response.kind === server.EventBeginInstallTypes) { + beginEvent = response; + return; + } + if (response.kind === server.EventEndInstallTypes) { + endEvent = response; + return; + } + super.sendResponse(response); + } + })(); + const projectService = createProjectService(host, { typingsInstaller: installer }); + projectService.openClientFile(f1.path); + + installer.installAll(/*expectedCount*/ 1); + + assert.isTrue(!!beginEvent); + assert.isTrue(!!endEvent); + assert.isTrue(beginEvent.eventId === endEvent.eventId); + assert.isFalse(endEvent.installSuccess); + checkNumberOfProjects(projectService, { inferredProjects: 1 }); + checkProjectActualFiles(projectService.inferredProjects[0], [f1.path]); + }); + }); } \ No newline at end of file diff --git a/src/server/protocol.ts b/src/server/protocol.ts index e1735f768e42b..1e29b0291040e 100644 --- a/src/server/protocol.ts +++ b/src/server/protocol.ts @@ -2117,6 +2117,40 @@ namespace ts.server.protocol { typingsInstallerVersion: string; } + export type BeginInstallTypesEventName = "beginInstallTypes"; + export type EndInstallTypesEventName = "endInstallTypes"; + + export interface BeginInstallTypesEvent extends Event { + event: BeginInstallTypesEventName; + body: BeginInstallTypesEventBody; + } + + export interface EndInstallTypesEvent extends Event { + event: EndInstallTypesEventName; + body: EndInstallTypesEventBody; + } + + export interface InstallTypesEventBody { + /** + * correlation id to match begin and end events + */ + eventId: number; + /** + * list of packages to install + */ + packages: ReadonlyArray; + } + + export interface BeginInstallTypesEventBody extends InstallTypesEventBody { + } + + export interface EndInstallTypesEventBody extends InstallTypesEventBody { + /** + * true if installation succeeded, otherwise false + */ + success: boolean; + } + export interface NavBarResponse extends Response { body?: NavigationBarItem[]; } diff --git a/src/server/server.ts b/src/server/server.ts index d5ccea4cd3251..7367741b9ea21 100644 --- a/src/server/server.ts +++ b/src/server/server.ts @@ -198,7 +198,7 @@ namespace ts.server { private socket: NodeSocket; private projectService: ProjectService; private throttledOperations: ThrottledOperations; - private telemetrySender: EventSender; + private eventSender: EventSender; constructor( private readonly telemetryEnabled: boolean, @@ -231,7 +231,7 @@ namespace ts.server { } setTelemetrySender(telemetrySender: EventSender) { - this.telemetrySender = telemetrySender; + this.eventSender = telemetrySender; } attach(projectService: ProjectService) { @@ -291,12 +291,30 @@ namespace ts.server { }); } - private handleMessage(response: SetTypings | InvalidateCachedTypings | TypingsInstallEvent) { + private handleMessage(response: SetTypings | InvalidateCachedTypings | BeginInstallTypes | EndInstallTypes) { if (this.logger.hasLevel(LogLevel.verbose)) { this.logger.info(`Received response: ${JSON.stringify(response)}`); } - if (response.kind === EventInstall) { - if (this.telemetrySender) { + + if (response.kind === EventBeginInstallTypes) { + if (!this.eventSender) { + return; + } + const body: protocol.BeginInstallTypesEventBody = { + eventId: response.eventId, + packages: response.packagesToInstall, + }; + const eventName: protocol.BeginInstallTypesEventName = "beginInstallTypes"; + this.eventSender.event(body, eventName); + + return; + } + + if (response.kind === EventEndInstallTypes) { + if (!this.eventSender) { + return; + } + if (this.telemetryEnabled) { const body: protocol.TypingsInstalledTelemetryEventBody = { telemetryEventName: "typingsInstalled", payload: { @@ -306,10 +324,19 @@ namespace ts.server { } }; const eventName: protocol.TelemetryEventName = "telemetry"; - this.telemetrySender.event(body, eventName); + this.eventSender.event(body, eventName); } + + const body: protocol.EndInstallTypesEventBody = { + eventId: response.eventId, + packages: response.packagesToInstall, + success: response.installSuccess, + }; + const eventName: protocol.EndInstallTypesEventName = "endInstallTypes"; + this.eventSender.event(body, eventName); return; } + this.projectService.updateTypingsForProject(response); if (response.kind == ActionSet && this.socket) { this.sendEvent(0, "setTypings", response); diff --git a/src/server/shared.ts b/src/server/shared.ts index 81a1f7fb55bc2..c56d4098e750e 100644 --- a/src/server/shared.ts +++ b/src/server/shared.ts @@ -3,7 +3,8 @@ namespace ts.server { export const ActionSet: ActionSet = "action::set"; export const ActionInvalidate: ActionInvalidate = "action::invalidate"; - export const EventInstall: EventInstall = "event::install"; + export const EventBeginInstallTypes: EventBeginInstallTypes = "event::beginInstallTypes"; + export const EventEndInstallTypes: EventEndInstallTypes = "event::endInstallTypes"; export namespace Arguments { export const GlobalCacheLocation = "--globalTypingsCacheLocation"; diff --git a/src/server/types.d.ts b/src/server/types.d.ts index 77e9e762b5996..9f53fa8def1a4 100644 --- a/src/server/types.d.ts +++ b/src/server/types.d.ts @@ -43,10 +43,11 @@ declare namespace ts.server { export type ActionSet = "action::set"; export type ActionInvalidate = "action::invalidate"; - export type EventInstall = "event::install"; + export type EventBeginInstallTypes = "event::beginInstallTypes"; + export type EventEndInstallTypes = "event::endInstallTypes"; export interface TypingInstallerResponse { - readonly kind: ActionSet | ActionInvalidate | EventInstall; + readonly kind: ActionSet | ActionInvalidate | EventBeginInstallTypes | EventEndInstallTypes; } export interface ProjectResponse extends TypingInstallerResponse { @@ -65,11 +66,20 @@ declare namespace ts.server { readonly kind: ActionInvalidate; } - export interface TypingsInstallEvent extends TypingInstallerResponse { + export interface InstallTypes extends ProjectResponse { + readonly kind: EventBeginInstallTypes | EventEndInstallTypes; + readonly eventId: number; + readonly typingsInstallerVersion: string; readonly packagesToInstall: ReadonlyArray; - readonly kind: EventInstall; + } + + export interface BeginInstallTypes extends InstallTypes { + readonly kind: EventBeginInstallTypes; + } + + export interface EndInstallTypes extends InstallTypes { + readonly kind: EventEndInstallTypes; readonly installSuccess: boolean; - readonly typingsInstallerVersion: string; } export interface InstallTypingHost extends JsTyping.TypingResolutionHost { diff --git a/src/server/typingsInstaller/nodeTypingsInstaller.ts b/src/server/typingsInstaller/nodeTypingsInstaller.ts index 235c2f16dad73..19f794ad57ca2 100644 --- a/src/server/typingsInstaller/nodeTypingsInstaller.ts +++ b/src/server/typingsInstaller/nodeTypingsInstaller.ts @@ -70,13 +70,12 @@ namespace ts.server.typingsInstaller { private readonly npmPath: string; readonly typesRegistry: Map; - constructor(globalTypingsCacheLocation: string, throttleLimit: number, telemetryEnabled: boolean, log: Log) { + constructor(globalTypingsCacheLocation: string, throttleLimit: number, log: Log) { super( sys, globalTypingsCacheLocation, toPath("typingSafeList.json", __dirname, createGetCanonicalFileName(sys.useCaseSensitiveFileNames)), throttleLimit, - telemetryEnabled, log); if (this.log.isEnabled()) { this.log.writeLine(`Process id: ${process.pid}`); @@ -113,7 +112,7 @@ namespace ts.server.typingsInstaller { }); } - protected sendResponse(response: SetTypings | InvalidateCachedTypings) { + protected sendResponse(response: SetTypings | InvalidateCachedTypings | BeginInstallTypes | EndInstallTypes) { if (this.log.isEnabled()) { this.log.writeLine(`Sending response: ${JSON.stringify(response)}`); } @@ -149,7 +148,6 @@ namespace ts.server.typingsInstaller { const logFilePath = findArgument(server.Arguments.LogFile); const globalTypingsCacheLocation = findArgument(server.Arguments.GlobalCacheLocation); - const telemetryEnabled = hasArgument(server.Arguments.EnableTelemetry); const log = new FileLog(logFilePath); if (log.isEnabled()) { @@ -163,6 +161,6 @@ namespace ts.server.typingsInstaller { } process.exit(0); }); - const installer = new NodeTypingsInstaller(globalTypingsCacheLocation, /*throttleLimit*/5, telemetryEnabled, log); + const installer = new NodeTypingsInstaller(globalTypingsCacheLocation, /*throttleLimit*/5, log); installer.listen(); } \ No newline at end of file diff --git a/src/server/typingsInstaller/typingsInstaller.ts b/src/server/typingsInstaller/typingsInstaller.ts index 25d53e14e755d..7a09c1f6c216d 100644 --- a/src/server/typingsInstaller/typingsInstaller.ts +++ b/src/server/typingsInstaller/typingsInstaller.ts @@ -97,7 +97,6 @@ namespace ts.server.typingsInstaller { readonly globalCachePath: string, readonly safeListPath: Path, readonly throttleLimit: number, - readonly telemetryEnabled: boolean, protected readonly log = nullLog) { if (this.log.isEnabled()) { this.log.writeLine(`Global cache location '${globalCachePath}', safe file path '${safeListPath}'`); @@ -309,47 +308,58 @@ namespace ts.server.typingsInstaller { const requestId = this.installRunCount; this.installRunCount++; + // send progress event + this.sendResponse({ + kind: EventBeginInstallTypes, + eventId: requestId, + typingsInstallerVersion: ts.version, // qualified explicitly to prevent occasional shadowing + projectName: req.projectName + }); + this.installTypingsAsync(requestId, scopedTypings, cachePath, ok => { - if (this.telemetryEnabled) { - this.sendResponse({ - kind: EventInstall, - packagesToInstall: scopedTypings, - installSuccess: ok, - typingsInstallerVersion: ts.version // qualified explicitly to prevent occasional shadowing - }); - } + try { + if (!ok) { + if (this.log.isEnabled()) { + this.log.writeLine(`install request failed, marking packages as missing to prevent repeated requests: ${JSON.stringify(filteredTypings)}`); + } + for (const typing of filteredTypings) { + this.missingTypingsSet[typing] = true; + } + return; + } - if (!ok) { + // TODO: watch project directory if (this.log.isEnabled()) { - this.log.writeLine(`install request failed, marking packages as missing to prevent repeated requests: ${JSON.stringify(filteredTypings)}`); - } - for (const typing of filteredTypings) { - this.missingTypingsSet[typing] = true; + this.log.writeLine(`Installed typings ${JSON.stringify(scopedTypings)}`); } - return; - } - - // TODO: watch project directory - if (this.log.isEnabled()) { - this.log.writeLine(`Installed typings ${JSON.stringify(scopedTypings)}`); - } - const installedTypingFiles: string[] = []; - for (const packageName of filteredTypings) { - const typingFile = typingToFileName(cachePath, packageName, this.installTypingHost, this.log); - if (!typingFile) { - this.missingTypingsSet[packageName] = true; - continue; + const installedTypingFiles: string[] = []; + for (const packageName of filteredTypings) { + const typingFile = typingToFileName(cachePath, packageName, this.installTypingHost, this.log); + if (!typingFile) { + this.missingTypingsSet[packageName] = true; + continue; + } + if (!this.packageNameToTypingLocation[packageName]) { + this.packageNameToTypingLocation[packageName] = typingFile; + } + installedTypingFiles.push(typingFile); } - if (!this.packageNameToTypingLocation[packageName]) { - this.packageNameToTypingLocation[packageName] = typingFile; + if (this.log.isEnabled()) { + this.log.writeLine(`Installed typing files ${JSON.stringify(installedTypingFiles)}`); } - installedTypingFiles.push(typingFile); + + this.sendResponse(this.createSetTypings(req, currentlyCachedTypings.concat(installedTypingFiles))); } - if (this.log.isEnabled()) { - this.log.writeLine(`Installed typing files ${JSON.stringify(installedTypingFiles)}`); + finally { + this.sendResponse({ + kind: EventEndInstallTypes, + eventId: requestId, + projectName: req.projectName, + packagesToInstall: scopedTypings, + installSuccess: ok, + typingsInstallerVersion: ts.version // qualified explicitly to prevent occasional shadowing + }); } - - this.sendResponse(this.createSetTypings(req, currentlyCachedTypings.concat(installedTypingFiles))); }); } @@ -417,6 +427,6 @@ namespace ts.server.typingsInstaller { } protected abstract installWorker(requestId: number, args: string[], cwd: string, onRequestCompleted: RequestCompletedAction): void; - protected abstract sendResponse(response: SetTypings | InvalidateCachedTypings | TypingsInstallEvent): void; + protected abstract sendResponse(response: SetTypings | InvalidateCachedTypings | BeginInstallTypes | EndInstallTypes): void; } } \ No newline at end of file From f55b3ef87a8263c44ab41d728c4669363dfa772c Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Tue, 29 Nov 2016 12:48:41 -0800 Subject: [PATCH 4/8] Preserve modifiers in isomorphic mapped types --- src/compiler/checker.ts | 26 +++++++++++++++++--------- 1 file changed, 17 insertions(+), 9 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 527735a3b0f4a..46f10488779e6 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -4497,12 +4497,14 @@ 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. + // and T as the template type. If K is of the form 'keyof S', the mapped type and S are + // isomorphic and we copy property modifiers from corresponding properties in S. const typeParameter = getTypeParameterFromMappedType(type); const constraintType = getConstraintTypeFromMappedType(type); + const isomorphicType = getIsomorphicTypeFromMappedType(type); const templateType = getTemplateTypeFromMappedType(type); - const isReadonly = !!type.declaration.readonlyToken; - const isOptional = !!type.declaration.questionToken; + const templateReadonly = !!type.declaration.readonlyToken; + const templateOptional = !!type.declaration.questionToken; // First, if the constraint type is a type parameter, obtain the base constraint. Then, // if the key type is a 'keyof X', obtain 'keyof C' where C is the base constraint of X. // Finally, iterate over the constituents of the resulting iteration type. @@ -4515,18 +4517,19 @@ namespace ts { const iterationMapper = createUnaryTypeMapper(typeParameter, t); const templateMapper = type.mapper ? combineTypeMappers(type.mapper, iterationMapper) : iterationMapper; const propType = instantiateType(templateType, templateMapper); - // If the current iteration type constituent is a literal type, create a property. - // Otherwise, for type string create a string index signature and for type number - // create a numeric index signature. - if (t.flags & (TypeFlags.StringLiteral | TypeFlags.NumberLiteral | TypeFlags.EnumLiteral)) { + // If the current iteration type constituent is a string literal type, create a property. + // Otherwise, for type string create a string index signature. + if (t.flags & TypeFlags.StringLiteral) { const propName = (t).text; + const isomorphicProp = isomorphicType && getPropertyOfType(isomorphicType, propName); + const isOptional = templateOptional || !!(isomorphicProp && isomorphicProp.flags & SymbolFlags.Optional); const prop = createSymbol(SymbolFlags.Property | SymbolFlags.Transient | (isOptional ? SymbolFlags.Optional : 0), propName); prop.type = addOptionality(propType, isOptional); - prop.isReadonly = isReadonly; + prop.isReadonly = templateReadonly || isomorphicProp && isReadonlySymbol(isomorphicProp); members[propName] = prop; } else if (t.flags & TypeFlags.String) { - stringIndexInfo = createIndexInfo(propType, isReadonly); + stringIndexInfo = createIndexInfo(propType, templateReadonly); } }); setStructuredTypeMembers(type, members, emptyArray, emptyArray, stringIndexInfo, undefined); @@ -4549,6 +4552,11 @@ namespace ts { unknownType); } + function getIsomorphicTypeFromMappedType(type: MappedType) { + const constraint = getConstraintDeclaration(getTypeParameterFromMappedType(type)); + return constraint.kind === SyntaxKind.TypeOperator ? instantiateType(getTypeFromTypeNode((constraint).type), type.mapper || identityMapper) : undefined; + } + function getErasedTemplateTypeFromMappedType(type: MappedType) { return instantiateType(getTemplateTypeFromMappedType(type), createUnaryTypeMapper(getTypeParameterFromMappedType(type), anyType)); } From f366ae0332425a3c031d71580d5d5406f92efdb1 Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Tue, 29 Nov 2016 12:48:55 -0800 Subject: [PATCH 5/8] Add tests --- .../reference/mappedTypeModifiers.js | 73 +++++++++ .../reference/mappedTypeModifiers.symbols | 148 ++++++++++++++++++ .../reference/mappedTypeModifiers.types | 148 ++++++++++++++++++ .../types/mapped/mappedTypeModifiers.ts | 42 +++++ 4 files changed, 411 insertions(+) create mode 100644 tests/baselines/reference/mappedTypeModifiers.js create mode 100644 tests/baselines/reference/mappedTypeModifiers.symbols create mode 100644 tests/baselines/reference/mappedTypeModifiers.types create mode 100644 tests/cases/conformance/types/mapped/mappedTypeModifiers.ts diff --git a/tests/baselines/reference/mappedTypeModifiers.js b/tests/baselines/reference/mappedTypeModifiers.js new file mode 100644 index 0000000000000..8f3f7ba5416a5 --- /dev/null +++ b/tests/baselines/reference/mappedTypeModifiers.js @@ -0,0 +1,73 @@ +//// [mappedTypeModifiers.ts] + +type T = { a: number, b: string }; +type U = { a: number | undefined, b: string | undefined }; +type P = { a?: number, b?: string }; +type R = { readonly a: number, readonly b: string }; +type PR = { readonly a?: number, readonly b?: string }; + +// Validate they all have the same keys +var v00: "a" | "b"; +var v00: keyof T; +var v00: keyof U; +var v00: keyof P; +var v00: keyof R; +var v00: keyof PR; + +// Validate that non-isomorphic mapped types strip modifiers +var v01: T; +var v01: Pick; +var v01: Pick, keyof T>; + +// Validate that non-isomorphic mapped types strip modifiers +var v02: U; +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: P; +var v03: Partial; + +// Validate that isomorphic mapped types preserve readonly modifier +var v04: R; +var v04: Readonly; + +// Validate that isomorphic mapped types preserve both partial and readonly modifiers +var v05: PR; +var v05: Partial; +var v05: Readonly

; +var v05: Partial>; +var v05: Readonly>; + +//// [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 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 v04; +var v04; +// Validate that isomorphic mapped types preserve both partial and readonly modifiers +var v05; +var v05; +var v05; +var v05; +var v05; diff --git a/tests/baselines/reference/mappedTypeModifiers.symbols b/tests/baselines/reference/mappedTypeModifiers.symbols new file mode 100644 index 0000000000000..6799d13d1acd5 --- /dev/null +++ b/tests/baselines/reference/mappedTypeModifiers.symbols @@ -0,0 +1,148 @@ +=== tests/cases/conformance/types/mapped/mappedTypeModifiers.ts === + +type T = { a: number, b: string }; +>T : Symbol(T, Decl(mappedTypeModifiers.ts, 0, 0)) +>a : Symbol(a, Decl(mappedTypeModifiers.ts, 1, 10)) +>b : Symbol(b, Decl(mappedTypeModifiers.ts, 1, 21)) + +type U = { a: number | undefined, b: string | undefined }; +>U : Symbol(U, Decl(mappedTypeModifiers.ts, 1, 34)) +>a : Symbol(a, Decl(mappedTypeModifiers.ts, 2, 10)) +>b : Symbol(b, Decl(mappedTypeModifiers.ts, 2, 33)) + +type P = { a?: number, b?: string }; +>P : Symbol(P, Decl(mappedTypeModifiers.ts, 2, 58)) +>a : Symbol(a, Decl(mappedTypeModifiers.ts, 3, 10)) +>b : Symbol(b, Decl(mappedTypeModifiers.ts, 3, 22)) + +type R = { readonly a: number, readonly b: string }; +>R : Symbol(R, Decl(mappedTypeModifiers.ts, 3, 36)) +>a : Symbol(a, Decl(mappedTypeModifiers.ts, 4, 10)) +>b : Symbol(b, Decl(mappedTypeModifiers.ts, 4, 30)) + +type PR = { readonly a?: number, readonly b?: string }; +>PR : Symbol(PR, Decl(mappedTypeModifiers.ts, 4, 52)) +>a : Symbol(a, Decl(mappedTypeModifiers.ts, 5, 11)) +>b : Symbol(b, Decl(mappedTypeModifiers.ts, 5, 32)) + +// 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)) + +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)) +>T : Symbol(T, Decl(mappedTypeModifiers.ts, 0, 0)) + +var v00: keyof U; +>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)) +>U : Symbol(U, Decl(mappedTypeModifiers.ts, 1, 34)) + +var v00: keyof P; +>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)) +>P : Symbol(P, Decl(mappedTypeModifiers.ts, 2, 58)) + +var v00: keyof R; +>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)) +>R : Symbol(R, Decl(mappedTypeModifiers.ts, 3, 36)) + +var v00: keyof PR; +>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)) +>PR : Symbol(PR, Decl(mappedTypeModifiers.ts, 4, 52)) + +// 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)) +>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)) +>Pick : Symbol(Pick, Decl(lib.d.ts, --, --)) +>R : Symbol(R, Decl(mappedTypeModifiers.ts, 3, 36)) +>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)) +>Pick : Symbol(Pick, 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 non-isomorphic mapped types strip modifiers +var v02: U; +>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)) +>U : Symbol(U, Decl(mappedTypeModifiers.ts, 1, 34)) + +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)) +>Pick : Symbol(Pick, Decl(lib.d.ts, --, --)) +>P : Symbol(P, Decl(mappedTypeModifiers.ts, 2, 58)) +>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)) +>Pick : Symbol(Pick, Decl(lib.d.ts, --, --)) +>PR : Symbol(PR, Decl(mappedTypeModifiers.ts, 4, 52)) +>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, --, --)) +>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: P; +>v03 : Symbol(v03, Decl(mappedTypeModifiers.ts, 28, 3), Decl(mappedTypeModifiers.ts, 29, 3)) +>P : Symbol(P, Decl(mappedTypeModifiers.ts, 2, 58)) + +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: R; +>v04 : Symbol(v04, Decl(mappedTypeModifiers.ts, 32, 3), Decl(mappedTypeModifiers.ts, 33, 3)) +>R : Symbol(R, Decl(mappedTypeModifiers.ts, 3, 36)) + +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: PR; +>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)) +>PR : Symbol(PR, Decl(mappedTypeModifiers.ts, 4, 52)) + +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, --, --)) +>R : Symbol(R, Decl(mappedTypeModifiers.ts, 3, 36)) + +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, --, --)) +>P : Symbol(P, Decl(mappedTypeModifiers.ts, 2, 58)) + +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, --, --)) +>T : Symbol(T, Decl(mappedTypeModifiers.ts, 0, 0)) + diff --git a/tests/baselines/reference/mappedTypeModifiers.types b/tests/baselines/reference/mappedTypeModifiers.types new file mode 100644 index 0000000000000..5c713991f7539 --- /dev/null +++ b/tests/baselines/reference/mappedTypeModifiers.types @@ -0,0 +1,148 @@ +=== tests/cases/conformance/types/mapped/mappedTypeModifiers.ts === + +type T = { a: number, b: string }; +>T : T +>a : number +>b : string + +type U = { a: number | undefined, b: string | undefined }; +>U : U +>a : number | undefined +>b : string | undefined + +type P = { a?: number, b?: string }; +>P : P +>a : number | undefined +>b : string | undefined + +type R = { readonly a: number, readonly b: string }; +>R : R +>a : number +>b : string + +type PR = { readonly a?: number, readonly b?: string }; +>PR : PR +>a : number | undefined +>b : string | undefined + +// Validate they all have the same keys +var v00: "a" | "b"; +>v00 : "a" | "b" + +var v00: keyof T; +>v00 : "a" | "b" +>T : T + +var v00: keyof U; +>v00 : "a" | "b" +>U : U + +var v00: keyof P; +>v00 : "a" | "b" +>P : P + +var v00: keyof R; +>v00 : "a" | "b" +>R : R + +var v00: keyof PR; +>v00 : "a" | "b" +>PR : PR + +// Validate that non-isomorphic mapped types strip modifiers +var v01: T; +>v01 : T +>T : T + +var v01: Pick; +>v01 : T +>Pick : Pick +>R : R +>T : T + +var v01: Pick, keyof T>; +>v01 : T +>Pick : Pick +>Readonly : Readonly +>T : T +>T : T + +// Validate that non-isomorphic mapped types strip modifiers +var v02: U; +>v02 : U +>U : U + +var v02: Pick; +>v02 : U +>Pick : Pick +>P : P +>T : T + +var v02: Pick; +>v02 : U +>Pick : Pick +>PR : PR +>T : T + +var v02: Pick, keyof T>; +>v02 : U +>Pick : Pick +>Partial : Partial +>T : T +>T : T + +var v02: Pick>, keyof T>; +>v02 : U +>Pick : Pick +>Partial : Partial +>Readonly : Readonly +>T : T +>T : T + +// Validate that isomorphic mapped types preserve optional modifier +var v03: P; +>v03 : P +>P : P + +var v03: Partial; +>v03 : P +>Partial : Partial +>T : T + +// Validate that isomorphic mapped types preserve readonly modifier +var v04: R; +>v04 : R +>R : R + +var v04: Readonly; +>v04 : R +>Readonly : Readonly +>T : T + +// Validate that isomorphic mapped types preserve both partial and readonly modifiers +var v05: PR; +>v05 : PR +>PR : PR + +var v05: Partial; +>v05 : PR +>Partial : Partial +>R : R + +var v05: Readonly

; +>v05 : PR +>Readonly : Readonly +>P : P + +var v05: Partial>; +>v05 : PR +>Partial : Partial +>Readonly : Readonly +>T : T + +var v05: Readonly>; +>v05 : PR +>Readonly : Readonly +>Partial : Partial +>T : T + diff --git a/tests/cases/conformance/types/mapped/mappedTypeModifiers.ts b/tests/cases/conformance/types/mapped/mappedTypeModifiers.ts new file mode 100644 index 0000000000000..947f0c579a1c8 --- /dev/null +++ b/tests/cases/conformance/types/mapped/mappedTypeModifiers.ts @@ -0,0 +1,42 @@ +// @strictNullChecks: true + +type T = { a: number, b: string }; +type U = { a: number | undefined, b: string | undefined }; +type P = { a?: number, b?: string }; +type R = { readonly a: number, readonly b: string }; +type PR = { readonly a?: number, readonly b?: string }; + +// Validate they all have the same keys +var v00: "a" | "b"; +var v00: keyof T; +var v00: keyof U; +var v00: keyof P; +var v00: keyof R; +var v00: keyof PR; + +// Validate that non-isomorphic mapped types strip modifiers +var v01: T; +var v01: Pick; +var v01: Pick, keyof T>; + +// Validate that non-isomorphic mapped types strip modifiers +var v02: U; +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: P; +var v03: Partial; + +// Validate that isomorphic mapped types preserve readonly modifier +var v04: R; +var v04: Readonly; + +// Validate that isomorphic mapped types preserve both partial and readonly modifiers +var v05: PR; +var v05: Partial; +var v05: Readonly

; +var v05: Partial>; +var v05: Readonly>; \ No newline at end of file From 3cd17316282efa0cd87c5dbaa5755b700614b626 Mon Sep 17 00:00:00 2001 From: Arthur Ozga Date: Tue, 29 Nov 2016 15:59:28 -0600 Subject: [PATCH 6/8] abstract accessors can't have implementations --- src/compiler/checker.ts | 3 +++ src/compiler/diagnosticMessages.json | 4 +++ .../classAbstractAccessor.errors.txt | 22 +++++++++++++++ .../reference/classAbstractAccessor.js | 27 +++++++++++++++++++ .../classAbstractAccessor.ts | 6 +++++ 5 files changed, 62 insertions(+) create mode 100644 tests/baselines/reference/classAbstractAccessor.errors.txt create mode 100644 tests/baselines/reference/classAbstractAccessor.js create mode 100644 tests/cases/conformance/classes/classDeclarations/classAbstractKeyword/classAbstractAccessor.ts diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 527735a3b0f4a..53b3bdea3ce2f 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -21239,6 +21239,9 @@ namespace ts { else if (accessor.body === undefined && !(getModifierFlags(accessor) & ModifierFlags.Abstract)) { return grammarErrorAtPos(getSourceFileOfNode(accessor), accessor.end - 1, ";".length, Diagnostics._0_expected, "{"); } + else if (accessor.body && getModifierFlags(accessor) & ModifierFlags.Abstract) { + return grammarErrorOnNode(accessor, Diagnostics.An_abstract_accessor_cannot_have_an_implementation); + } else if (accessor.typeParameters) { return grammarErrorOnNode(accessor.name, Diagnostics.An_accessor_cannot_have_type_parameters); } diff --git a/src/compiler/diagnosticMessages.json b/src/compiler/diagnosticMessages.json index 5a22d7d40d5a4..8f3b9beb888ad 100644 --- a/src/compiler/diagnosticMessages.json +++ b/src/compiler/diagnosticMessages.json @@ -851,6 +851,10 @@ "category": "Error", "code": 1317 }, + "An abstract accessor cannot have an implementation.": { + "category": "Error", + "code": 1318 + }, "Duplicate identifier '{0}'.": { "category": "Error", "code": 2300 diff --git a/tests/baselines/reference/classAbstractAccessor.errors.txt b/tests/baselines/reference/classAbstractAccessor.errors.txt new file mode 100644 index 0000000000000..178a2445ccece --- /dev/null +++ b/tests/baselines/reference/classAbstractAccessor.errors.txt @@ -0,0 +1,22 @@ +tests/cases/conformance/classes/classDeclarations/classAbstractKeyword/classAbstractAccessor.ts(2,17): error TS1056: Accessors are only available when targeting ECMAScript 5 and higher. +tests/cases/conformance/classes/classDeclarations/classAbstractKeyword/classAbstractAccessor.ts(3,17): error TS1056: Accessors are only available when targeting ECMAScript 5 and higher. +tests/cases/conformance/classes/classDeclarations/classAbstractKeyword/classAbstractAccessor.ts(4,17): error TS1056: Accessors are only available when targeting ECMAScript 5 and higher. +tests/cases/conformance/classes/classDeclarations/classAbstractKeyword/classAbstractAccessor.ts(5,17): error TS1056: Accessors are only available when targeting ECMAScript 5 and higher. + + +==== tests/cases/conformance/classes/classDeclarations/classAbstractKeyword/classAbstractAccessor.ts (4 errors) ==== + abstract class A { + abstract get a(); + ~ +!!! error TS1056: Accessors are only available when targeting ECMAScript 5 and higher. + abstract get aa() { return 1; } // error + ~~ +!!! error TS1056: Accessors are only available when targeting ECMAScript 5 and higher. + abstract set b(x: string); + ~ +!!! error TS1056: Accessors are only available when targeting ECMAScript 5 and higher. + abstract set bb(x: string) {} // error + ~~ +!!! error TS1056: Accessors are only available when targeting ECMAScript 5 and higher. + } + \ No newline at end of file diff --git a/tests/baselines/reference/classAbstractAccessor.js b/tests/baselines/reference/classAbstractAccessor.js new file mode 100644 index 0000000000000..d953a4ac0c22e --- /dev/null +++ b/tests/baselines/reference/classAbstractAccessor.js @@ -0,0 +1,27 @@ +//// [classAbstractAccessor.ts] +abstract class A { + abstract get a(); + abstract get aa() { return 1; } // error + abstract set b(x: string); + abstract set bb(x: string) {} // error +} + + +//// [classAbstractAccessor.js] +var A = (function () { + function A() { + } + Object.defineProperty(A.prototype, "aa", { + get: function () { return 1; } // error + , + enumerable: true, + configurable: true + }); + Object.defineProperty(A.prototype, "bb", { + set: function (x) { } // error + , + enumerable: true, + configurable: true + }); + return A; +}()); diff --git a/tests/cases/conformance/classes/classDeclarations/classAbstractKeyword/classAbstractAccessor.ts b/tests/cases/conformance/classes/classDeclarations/classAbstractKeyword/classAbstractAccessor.ts new file mode 100644 index 0000000000000..64d087f361ff5 --- /dev/null +++ b/tests/cases/conformance/classes/classDeclarations/classAbstractKeyword/classAbstractAccessor.ts @@ -0,0 +1,6 @@ +abstract class A { + abstract get a(); + abstract get aa() { return 1; } // error + abstract set b(x: string); + abstract set bb(x: string) {} // error +} From 4b0697ff9d368225aae2d3c743de5e33566037d4 Mon Sep 17 00:00:00 2001 From: Arthur Ozga Date: Tue, 29 Nov 2016 16:04:56 -0600 Subject: [PATCH 7/8] fix test --- .../reference/classAbstractAccessor.errors.txt | 17 ++++++----------- .../reference/classAbstractAccessor.js | 1 + .../classAbstractAccessor.ts | 2 ++ 3 files changed, 9 insertions(+), 11 deletions(-) diff --git a/tests/baselines/reference/classAbstractAccessor.errors.txt b/tests/baselines/reference/classAbstractAccessor.errors.txt index 178a2445ccece..b43cfa9d7f13e 100644 --- a/tests/baselines/reference/classAbstractAccessor.errors.txt +++ b/tests/baselines/reference/classAbstractAccessor.errors.txt @@ -1,22 +1,17 @@ -tests/cases/conformance/classes/classDeclarations/classAbstractKeyword/classAbstractAccessor.ts(2,17): error TS1056: Accessors are only available when targeting ECMAScript 5 and higher. -tests/cases/conformance/classes/classDeclarations/classAbstractKeyword/classAbstractAccessor.ts(3,17): error TS1056: Accessors are only available when targeting ECMAScript 5 and higher. -tests/cases/conformance/classes/classDeclarations/classAbstractKeyword/classAbstractAccessor.ts(4,17): error TS1056: Accessors are only available when targeting ECMAScript 5 and higher. -tests/cases/conformance/classes/classDeclarations/classAbstractKeyword/classAbstractAccessor.ts(5,17): error TS1056: Accessors are only available when targeting ECMAScript 5 and higher. +tests/cases/conformance/classes/classDeclarations/classAbstractKeyword/classAbstractAccessor.ts(4,17): error TS1318: An abstract accessor cannot have an implementation. +tests/cases/conformance/classes/classDeclarations/classAbstractKeyword/classAbstractAccessor.ts(6,17): error TS1318: An abstract accessor cannot have an implementation. -==== tests/cases/conformance/classes/classDeclarations/classAbstractKeyword/classAbstractAccessor.ts (4 errors) ==== +==== tests/cases/conformance/classes/classDeclarations/classAbstractKeyword/classAbstractAccessor.ts (2 errors) ==== + abstract class A { abstract get a(); - ~ -!!! error TS1056: Accessors are only available when targeting ECMAScript 5 and higher. abstract get aa() { return 1; } // error ~~ -!!! error TS1056: Accessors are only available when targeting ECMAScript 5 and higher. +!!! error TS1318: An abstract accessor cannot have an implementation. abstract set b(x: string); - ~ -!!! error TS1056: Accessors are only available when targeting ECMAScript 5 and higher. abstract set bb(x: string) {} // error ~~ -!!! error TS1056: Accessors are only available when targeting ECMAScript 5 and higher. +!!! error TS1318: An abstract accessor cannot have an implementation. } \ No newline at end of file diff --git a/tests/baselines/reference/classAbstractAccessor.js b/tests/baselines/reference/classAbstractAccessor.js index d953a4ac0c22e..a1edf0cb88d6f 100644 --- a/tests/baselines/reference/classAbstractAccessor.js +++ b/tests/baselines/reference/classAbstractAccessor.js @@ -1,4 +1,5 @@ //// [classAbstractAccessor.ts] + abstract class A { abstract get a(); abstract get aa() { return 1; } // error diff --git a/tests/cases/conformance/classes/classDeclarations/classAbstractKeyword/classAbstractAccessor.ts b/tests/cases/conformance/classes/classDeclarations/classAbstractKeyword/classAbstractAccessor.ts index 64d087f361ff5..2c59b6f93ccdf 100644 --- a/tests/cases/conformance/classes/classDeclarations/classAbstractKeyword/classAbstractAccessor.ts +++ b/tests/cases/conformance/classes/classDeclarations/classAbstractKeyword/classAbstractAccessor.ts @@ -1,3 +1,5 @@ +// @target: es5 + abstract class A { abstract get a(); abstract get aa() { return 1; } // error From 65e98c84d59bb90f450c5c58949cc47d33cdfb0c Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Tue, 29 Nov 2016 14:06:10 -0800 Subject: [PATCH 8/8] Add more tests --- .../reference/mappedTypeModifiers.js | 108 ++++++-- .../reference/mappedTypeModifiers.symbols | 255 ++++++++++++++--- .../reference/mappedTypeModifiers.types | 261 ++++++++++++++---- .../types/mapped/mappedTypeModifiers.ts | 79 ++++-- 4 files changed, 574 insertions(+), 129 deletions(-) diff --git a/tests/baselines/reference/mappedTypeModifiers.js b/tests/baselines/reference/mappedTypeModifiers.js index 8f3f7ba5416a5..8489194f95a3c 100644 --- a/tests/baselines/reference/mappedTypeModifiers.js +++ b/tests/baselines/reference/mappedTypeModifiers.js @@ -1,45 +1,88 @@ //// [mappedTypeModifiers.ts] type T = { a: number, b: string }; -type U = { a: number | undefined, b: string | undefined }; -type P = { a?: number, b?: string }; -type R = { readonly a: number, readonly b: string }; -type PR = { readonly a?: number, readonly 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 U; -var v00: keyof P; -var v00: keyof R; -var v00: keyof PR; +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; var v01: Pick, keyof T>; // Validate that non-isomorphic mapped types strip modifiers -var v02: U; -var v02: Pick; -var v02: Pick; +var v02: TU; +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: P; +var v03: TP; var v03: Partial; // Validate that isomorphic mapped types preserve readonly modifier -var v04: R; +var v04: TR; var v04: Readonly; // Validate that isomorphic mapped types preserve both partial and readonly modifiers -var v05: PR; -var v05: Partial; -var v05: Readonly

; +var v05: TPR; +var v05: Partial; +var v05: Readonly; var v05: Partial>; -var v05: Readonly>; +var v05: Readonly>; + +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>; + +// Validate that non-isomorphic mapped types strip modifiers +var b02: BU; +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; + +// 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>; //// [mappedTypeModifiers.js] // Validate they all have the same keys @@ -71,3 +114,32 @@ 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 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 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 6799d13d1acd5..8be2f53cec11e 100644 --- a/tests/baselines/reference/mappedTypeModifiers.symbols +++ b/tests/baselines/reference/mappedTypeModifiers.symbols @@ -5,25 +5,25 @@ type T = { a: number, b: string }; >a : Symbol(a, Decl(mappedTypeModifiers.ts, 1, 10)) >b : Symbol(b, Decl(mappedTypeModifiers.ts, 1, 21)) -type U = { a: number | undefined, b: string | undefined }; ->U : Symbol(U, Decl(mappedTypeModifiers.ts, 1, 34)) ->a : Symbol(a, Decl(mappedTypeModifiers.ts, 2, 10)) ->b : Symbol(b, Decl(mappedTypeModifiers.ts, 2, 33)) - -type P = { a?: number, b?: string }; ->P : Symbol(P, Decl(mappedTypeModifiers.ts, 2, 58)) ->a : Symbol(a, Decl(mappedTypeModifiers.ts, 3, 10)) ->b : Symbol(b, Decl(mappedTypeModifiers.ts, 3, 22)) - -type R = { readonly a: number, readonly b: string }; ->R : Symbol(R, Decl(mappedTypeModifiers.ts, 3, 36)) ->a : Symbol(a, Decl(mappedTypeModifiers.ts, 4, 10)) ->b : Symbol(b, Decl(mappedTypeModifiers.ts, 4, 30)) - -type PR = { readonly a?: number, readonly b?: string }; ->PR : Symbol(PR, Decl(mappedTypeModifiers.ts, 4, 52)) ->a : Symbol(a, Decl(mappedTypeModifiers.ts, 5, 11)) ->b : Symbol(b, Decl(mappedTypeModifiers.ts, 5, 32)) +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)) + +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)) + +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)) // Validate they all have the same keys var v00: "a" | "b"; @@ -33,31 +33,31 @@ 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)) >T : Symbol(T, Decl(mappedTypeModifiers.ts, 0, 0)) -var v00: keyof U; +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)) ->U : Symbol(U, Decl(mappedTypeModifiers.ts, 1, 34)) +>TU : Symbol(TU, Decl(mappedTypeModifiers.ts, 1, 34)) -var v00: keyof P; +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)) ->P : Symbol(P, Decl(mappedTypeModifiers.ts, 2, 58)) +>TP : Symbol(TP, Decl(mappedTypeModifiers.ts, 2, 59)) -var v00: keyof R; +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)) ->R : Symbol(R, Decl(mappedTypeModifiers.ts, 3, 36)) +>TR : Symbol(TR, Decl(mappedTypeModifiers.ts, 3, 37)) -var v00: keyof PR; +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)) ->PR : Symbol(PR, Decl(mappedTypeModifiers.ts, 4, 52)) +>TPR : Symbol(TPR, Decl(mappedTypeModifiers.ts, 4, 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)) >T : Symbol(T, Decl(mappedTypeModifiers.ts, 0, 0)) -var v01: Pick; +var v01: Pick; >v01 : Symbol(v01, Decl(mappedTypeModifiers.ts, 16, 3), Decl(mappedTypeModifiers.ts, 17, 3), Decl(mappedTypeModifiers.ts, 18, 3)) >Pick : Symbol(Pick, Decl(lib.d.ts, --, --)) ->R : Symbol(R, Decl(mappedTypeModifiers.ts, 3, 36)) +>TR : Symbol(TR, Decl(mappedTypeModifiers.ts, 3, 37)) >T : Symbol(T, Decl(mappedTypeModifiers.ts, 0, 0)) var v01: Pick, keyof T>; @@ -68,20 +68,20 @@ var v01: Pick, keyof T>; >T : Symbol(T, Decl(mappedTypeModifiers.ts, 0, 0)) // Validate that non-isomorphic mapped types strip modifiers -var v02: U; +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)) ->U : Symbol(U, Decl(mappedTypeModifiers.ts, 1, 34)) +>TU : Symbol(TU, Decl(mappedTypeModifiers.ts, 1, 34)) -var v02: Pick; +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)) >Pick : Symbol(Pick, Decl(lib.d.ts, --, --)) ->P : Symbol(P, Decl(mappedTypeModifiers.ts, 2, 58)) +>TP : Symbol(TP, Decl(mappedTypeModifiers.ts, 2, 59)) >T : Symbol(T, Decl(mappedTypeModifiers.ts, 0, 0)) -var v02: Pick; +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)) >Pick : Symbol(Pick, Decl(lib.d.ts, --, --)) ->PR : Symbol(PR, Decl(mappedTypeModifiers.ts, 4, 52)) +>TPR : Symbol(TPR, Decl(mappedTypeModifiers.ts, 4, 53)) >T : Symbol(T, Decl(mappedTypeModifiers.ts, 0, 0)) var v02: Pick, keyof T>; @@ -100,9 +100,9 @@ var v02: Pick>, keyof T>; >T : Symbol(T, Decl(mappedTypeModifiers.ts, 0, 0)) // Validate that isomorphic mapped types preserve optional modifier -var v03: P; +var v03: TP; >v03 : Symbol(v03, Decl(mappedTypeModifiers.ts, 28, 3), Decl(mappedTypeModifiers.ts, 29, 3)) ->P : Symbol(P, Decl(mappedTypeModifiers.ts, 2, 58)) +>TP : Symbol(TP, Decl(mappedTypeModifiers.ts, 2, 59)) var v03: Partial; >v03 : Symbol(v03, Decl(mappedTypeModifiers.ts, 28, 3), Decl(mappedTypeModifiers.ts, 29, 3)) @@ -110,9 +110,9 @@ var v03: Partial; >T : Symbol(T, Decl(mappedTypeModifiers.ts, 0, 0)) // Validate that isomorphic mapped types preserve readonly modifier -var v04: R; +var v04: TR; >v04 : Symbol(v04, Decl(mappedTypeModifiers.ts, 32, 3), Decl(mappedTypeModifiers.ts, 33, 3)) ->R : Symbol(R, Decl(mappedTypeModifiers.ts, 3, 36)) +>TR : Symbol(TR, Decl(mappedTypeModifiers.ts, 3, 37)) var v04: Readonly; >v04 : Symbol(v04, Decl(mappedTypeModifiers.ts, 32, 3), Decl(mappedTypeModifiers.ts, 33, 3)) @@ -120,19 +120,19 @@ var v04: Readonly; >T : Symbol(T, Decl(mappedTypeModifiers.ts, 0, 0)) // Validate that isomorphic mapped types preserve both partial and readonly modifiers -var v05: PR; +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)) ->PR : Symbol(PR, Decl(mappedTypeModifiers.ts, 4, 52)) +>TPR : Symbol(TPR, Decl(mappedTypeModifiers.ts, 4, 53)) -var v05: Partial; +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, --, --)) ->R : Symbol(R, Decl(mappedTypeModifiers.ts, 3, 36)) +>TR : Symbol(TR, Decl(mappedTypeModifiers.ts, 3, 37)) -var v05: Readonly

; +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, --, --)) ->P : Symbol(P, Decl(mappedTypeModifiers.ts, 2, 58)) +>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)) @@ -146,3 +146,168 @@ var v05: Readonly>; >Partial : Symbol(Partial, Decl(lib.d.ts, --, --)) >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)) + +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)) + +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)) + +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)) + +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)) + +// 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)) + +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)) + +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)) + +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)) + +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)) + +// 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)) + +var b01: Pick; +>b01 : Symbol(b01, Decl(mappedTypeModifiers.ts, 59, 3), Decl(mappedTypeModifiers.ts, 60, 3), Decl(mappedTypeModifiers.ts, 61, 3)) +>Pick : Symbol(Pick, Decl(lib.d.ts, --, --)) +>BR : Symbol(BR, Decl(mappedTypeModifiers.ts, 46, 51)) +>B : Symbol(B, Decl(mappedTypeModifiers.ts, 42, 51)) + +var b01: Pick, keyof B>; +>b01 : Symbol(b01, Decl(mappedTypeModifiers.ts, 59, 3), Decl(mappedTypeModifiers.ts, 60, 3), Decl(mappedTypeModifiers.ts, 61, 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)) + +// 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: 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)) +>Pick : Symbol(Pick, Decl(lib.d.ts, --, --)) +>BP : Symbol(BP, Decl(mappedTypeModifiers.ts, 45, 73)) +>B : Symbol(B, Decl(mappedTypeModifiers.ts, 42, 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)) +>Pick : Symbol(Pick, Decl(lib.d.ts, --, --)) +>BPR : Symbol(BPR, Decl(mappedTypeModifiers.ts, 47, 67)) +>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, --, --)) +>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)) + diff --git a/tests/baselines/reference/mappedTypeModifiers.types b/tests/baselines/reference/mappedTypeModifiers.types index 5c713991f7539..61b9bfc03b263 100644 --- a/tests/baselines/reference/mappedTypeModifiers.types +++ b/tests/baselines/reference/mappedTypeModifiers.types @@ -5,23 +5,23 @@ type T = { a: number, b: string }; >a : number >b : string -type U = { a: number | undefined, b: string | undefined }; ->U : U +type TU = { a: number | undefined, b: string | undefined }; +>TU : TU >a : number | undefined >b : string | undefined -type P = { a?: number, b?: string }; ->P : P +type TP = { a?: number, b?: string }; +>TP : TP >a : number | undefined >b : string | undefined -type R = { readonly a: number, readonly b: string }; ->R : R +type TR = { readonly a: number, readonly b: string }; +>TR : TR >a : number >b : string -type PR = { readonly a?: number, readonly b?: string }; ->PR : PR +type TPR = { readonly a?: number, readonly b?: string }; +>TPR : TPR >a : number | undefined >b : string | undefined @@ -33,31 +33,31 @@ var v00: keyof T; >v00 : "a" | "b" >T : T -var v00: keyof U; +var v00: keyof TU; >v00 : "a" | "b" ->U : U +>TU : TU -var v00: keyof P; +var v00: keyof TP; >v00 : "a" | "b" ->P : P +>TP : TP -var v00: keyof R; +var v00: keyof TR; >v00 : "a" | "b" ->R : R +>TR : TR -var v00: keyof PR; +var v00: keyof TPR; >v00 : "a" | "b" ->PR : PR +>TPR : TPR // Validate that non-isomorphic mapped types strip modifiers var v01: T; >v01 : T >T : T -var v01: Pick; +var v01: Pick; >v01 : T >Pick : Pick ->R : R +>TR : TR >T : T var v01: Pick, keyof T>; @@ -68,31 +68,31 @@ var v01: Pick, keyof T>; >T : T // Validate that non-isomorphic mapped types strip modifiers -var v02: U; ->v02 : U ->U : U +var v02: TU; +>v02 : TU +>TU : TU -var v02: Pick; ->v02 : U +var v02: Pick; +>v02 : TU >Pick : Pick ->P : P +>TP : TP >T : T -var v02: Pick; ->v02 : U +var v02: Pick; +>v02 : TU >Pick : Pick ->PR : PR +>TPR : TPR >T : T var v02: Pick, keyof T>; ->v02 : U +>v02 : TU >Pick : Pick >Partial : Partial >T : T >T : T var v02: Pick>, keyof T>; ->v02 : U +>v02 : TU >Pick : Pick >Partial : Partial >Readonly : Readonly @@ -100,49 +100,214 @@ var v02: Pick>, keyof T>; >T : T // Validate that isomorphic mapped types preserve optional modifier -var v03: P; ->v03 : P ->P : P +var v03: TP; +>v03 : TP +>TP : TP var v03: Partial; ->v03 : P +>v03 : TP >Partial : Partial >T : T // Validate that isomorphic mapped types preserve readonly modifier -var v04: R; ->v04 : R ->R : R +var v04: TR; +>v04 : TR +>TR : TR var v04: Readonly; ->v04 : R +>v04 : TR >Readonly : Readonly >T : T // Validate that isomorphic mapped types preserve both partial and readonly modifiers -var v05: PR; ->v05 : PR ->PR : PR +var v05: TPR; +>v05 : TPR +>TPR : TPR -var v05: Partial; ->v05 : PR +var v05: Partial; +>v05 : TPR >Partial : Partial ->R : R +>TR : TR -var v05: Readonly

; ->v05 : PR +var v05: Readonly; +>v05 : TPR >Readonly : Readonly ->P : P +>TP : TP var v05: Partial>; ->v05 : PR +>v05 : TPR >Partial : Partial >Readonly : Readonly >T : T var v05: Readonly>; ->v05 : PR +>v05 : TPR >Readonly : Readonly >Partial : Partial >T : T +type Boxified = { [P in keyof T]: { x: T[P] } }; +>Boxified : Boxified +>T : T +>P : P +>T : T +>x : T[P] +>T : T +>P : P + +type B = { a: { x: number }, b: { x: string } }; +>B : B +>a : { x: number; } +>x : number +>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 +>x : number +>b : { x: string; } | undefined +>x : string + +type BR = { readonly a: { x: number }, readonly b: { x: string } }; +>BR : BR +>a : { x: number; } +>x : number +>b : { x: string; } +>x : string + +type BPR = { readonly a?: { x: number }, readonly b?: { x: string } }; +>BPR : BPR +>a : { x: number; } | undefined +>x : number +>b : { x: string; } | undefined +>x : string + +// Validate they all have the same keys +var b00: "a" | "b"; +>b00 : "a" | "b" + +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 + +var b00: keyof BR; +>b00 : "a" | "b" +>BR : BR + +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; +>b01 : B +>Pick : Pick +>BR : BR +>B : B + +var b01: Pick, keyof B>; +>b01 : B +>Pick : Pick +>Readonly : Readonly +>BR : BR +>B : B + +// Validate that non-isomorphic mapped types strip modifiers +var b02: BU; +>b02 : BU +>BU : BU + +var b02: Pick; +>b02 : BU +>Pick : Pick +>BP : BP +>B : B + +var b02: Pick; +>b02 : BU +>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/cases/conformance/types/mapped/mappedTypeModifiers.ts b/tests/cases/conformance/types/mapped/mappedTypeModifiers.ts index 947f0c579a1c8..1e76c5b745284 100644 --- a/tests/cases/conformance/types/mapped/mappedTypeModifiers.ts +++ b/tests/cases/conformance/types/mapped/mappedTypeModifiers.ts @@ -1,42 +1,85 @@ // @strictNullChecks: true type T = { a: number, b: string }; -type U = { a: number | undefined, b: string | undefined }; -type P = { a?: number, b?: string }; -type R = { readonly a: number, readonly b: string }; -type PR = { readonly a?: number, readonly 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 U; -var v00: keyof P; -var v00: keyof R; -var v00: keyof PR; +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; var v01: Pick, keyof T>; // Validate that non-isomorphic mapped types strip modifiers -var v02: U; -var v02: Pick; -var v02: Pick; +var v02: TU; +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: P; +var v03: TP; var v03: Partial; // Validate that isomorphic mapped types preserve readonly modifier -var v04: R; +var v04: TR; var v04: Readonly; // Validate that isomorphic mapped types preserve both partial and readonly modifiers -var v05: PR; -var v05: Partial; -var v05: Readonly

; +var v05: TPR; +var v05: Partial; +var v05: Readonly; var v05: Partial>; -var v05: Readonly>; \ No newline at end of file +var v05: Readonly>; + +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>; + +// Validate that non-isomorphic mapped types strip modifiers +var b02: BU; +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; + +// 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