Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[ID-Prep] PR4 - Preserve types nodes from type assertions in declaration emit #57589

Closed
265 changes: 214 additions & 51 deletions src/compiler/transformers/declarations.ts

Large diffs are not rendered by default.

14 changes: 13 additions & 1 deletion src/compiler/transformers/declarations/diagnostics.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import {
DiagnosticMessage,
Diagnostics,
ElementAccessExpression,
ExportAssignment,
ExpressionWithTypeArguments,
FunctionDeclaration,
GetAccessorDeclaration,
Expand All @@ -24,6 +25,7 @@ import {
isConstructorDeclaration,
isConstructSignatureDeclaration,
isElementAccessExpression,
isExportAssignment,
isExpressionWithTypeArguments,
isFunctionDeclaration,
isGetAccessor,
Expand Down Expand Up @@ -100,7 +102,8 @@ export type DeclarationDiagnosticProducing =
| BinaryExpression
| JSDocTypedefTag
| JSDocCallbackTag
| JSDocEnumTag;
| JSDocEnumTag
| ExportAssignment;

/** @internal */
export function canProduceDiagnostics(node: Node): node is DeclarationDiagnosticProducing {
Expand Down Expand Up @@ -231,9 +234,18 @@ export function createGetSymbolAccessibilityDiagnosticForNode(node: DeclarationD
else if (isTypeAliasDeclaration(node) || isJSDocTypeAlias(node)) {
return getTypeAliasDeclarationVisibilityError;
}
else if (isExportAssignment(node)) {
return getExportAssignmentTypeVisibilityDiagnosticMessage;
}
else {
return Debug.assertNever(node, `Attempted to set a declaration diagnostic context for unhandled node kind: ${Debug.formatSyntaxKind((node as Node).kind)}`);
}
function getExportAssignmentTypeVisibilityDiagnosticMessage() {
return {
diagnosticMessage: Diagnostics.Default_export_of_the_module_has_or_is_using_private_name_0,
errorNode: node,
};
}

function getVariableDeclarationTypeVisibilityDiagnosticMessage(symbolAccessibilityResult: SymbolAccessibilityResult) {
if (node.kind === SyntaxKind.VariableDeclaration || node.kind === SyntaxKind.BindingElement) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,9 @@
accessorDeclarationEmitVisibilityErrors.ts(2,18): error TS2304: Cannot find name 'DoesNotExist'.
accessorDeclarationEmitVisibilityErrors.ts(2,18): error TS4106: Parameter 'arg' of accessor has or is using private name 'DoesNotExist'.


==== accessorDeclarationEmitVisibilityErrors.ts (2 errors) ====
==== accessorDeclarationEmitVisibilityErrors.ts (1 errors) ====
export class Q {
set bet(arg: DoesNotExist) {}
~~~~~~~~~~~~
!!! error TS2304: Cannot find name 'DoesNotExist'.
~~~~~~~~~~~~
!!! error TS4106: Parameter 'arg' of accessor has or is using private name 'DoesNotExist'.
dragomirtitian marked this conversation as resolved.
Show resolved Hide resolved
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,9 @@ export class Q {
export class Q {
set bet(arg) { }
}


//// [accessorDeclarationEmitVisibilityErrors.d.ts]
export declare class Q {
set bet(arg: DoesNotExist);
}
4 changes: 2 additions & 2 deletions tests/baselines/reference/coAndContraVariantInferences.js
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ interface Action<TName extends string, TPayload> {
name: TName;
payload: TPayload;
}
declare const actionA: Action<"ACTION_A", string>;
declare const actionB: Action<"ACTION_B", boolean>;
declare const actionA: Action<'ACTION_A', string>;
declare const actionB: Action<'ACTION_B', boolean>;
declare function call<TName extends string, TPayload>(action: Action<TName, TPayload>, fn: (action: Action<TName, TPayload>) => any): void;
declare const printFn: (action: typeof actionA | typeof actionB) => void;
Original file line number Diff line number Diff line change
Expand Up @@ -10,4 +10,5 @@ var x = {};
//// [duplicatePropertiesInTypeAssertions02.d.ts]
declare let x: {
a: number;
a: number;
rbuckton marked this conversation as resolved.
Show resolved Hide resolved
};
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,6 @@ hugeDeclarationOutputGetsTruncatedWithError.ts(5,14): error TS7056: The inferred

type manyprops = `${props}${props}`;

export const c = null as any as {[K in manyprops]: {[K2 in manyprops]: `${K}.${K2}`}};
export const c = () => null as any as {[K in manyprops]: {[K2 in manyprops]: `${K}.${K2}`}};
~
!!! error TS7056: The inferred type of this node exceeds the maximum length the compiler will serialize. An explicit type annotation is needed.
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,11 @@ type props = "a" | "b" | "c" | "d" | "e" | "f" | "g" | "h" | "i" | "j" | "k" | "

type manyprops = `${props}${props}`;

export const c = null as any as {[K in manyprops]: {[K2 in manyprops]: `${K}.${K2}`}};
export const c = () => null as any as {[K in manyprops]: {[K2 in manyprops]: `${K}.${K2}`}};

//// [hugeDeclarationOutputGetsTruncatedWithError.js]
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.c = void 0;
exports.c = null;
var c = function () { return null; };
exports.c = c;
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,12 @@ type manyprops = `${props}${props}`;
>props : Symbol(props, Decl(hugeDeclarationOutputGetsTruncatedWithError.ts, 0, 0))
>props : Symbol(props, Decl(hugeDeclarationOutputGetsTruncatedWithError.ts, 0, 0))

export const c = null as any as {[K in manyprops]: {[K2 in manyprops]: `${K}.${K2}`}};
export const c = () => null as any as {[K in manyprops]: {[K2 in manyprops]: `${K}.${K2}`}};
>c : Symbol(c, Decl(hugeDeclarationOutputGetsTruncatedWithError.ts, 4, 12))
>K : Symbol(K, Decl(hugeDeclarationOutputGetsTruncatedWithError.ts, 4, 34))
>K : Symbol(K, Decl(hugeDeclarationOutputGetsTruncatedWithError.ts, 4, 40))
>manyprops : Symbol(manyprops, Decl(hugeDeclarationOutputGetsTruncatedWithError.ts, 0, 167))
>K2 : Symbol(K2, Decl(hugeDeclarationOutputGetsTruncatedWithError.ts, 4, 53))
>K2 : Symbol(K2, Decl(hugeDeclarationOutputGetsTruncatedWithError.ts, 4, 59))
>manyprops : Symbol(manyprops, Decl(hugeDeclarationOutputGetsTruncatedWithError.ts, 0, 167))
>K : Symbol(K, Decl(hugeDeclarationOutputGetsTruncatedWithError.ts, 4, 34))
>K2 : Symbol(K2, Decl(hugeDeclarationOutputGetsTruncatedWithError.ts, 4, 53))
>K : Symbol(K, Decl(hugeDeclarationOutputGetsTruncatedWithError.ts, 4, 40))
>K2 : Symbol(K2, Decl(hugeDeclarationOutputGetsTruncatedWithError.ts, 4, 59))

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion tests/baselines/reference/namedTupleMembers.js
Original file line number Diff line number Diff line change
Expand Up @@ -133,7 +133,7 @@ export declare const func: Func<SegmentAnnotated>;
export declare function useState<T>(initial: T): [value: T, setter: (T: any) => void];
export type Iter = Func<[step: number, iterations: number]>;
export declare function readSegment([length, count]: [number, number]): void;
export declare const val: [number, number];
export declare const val: Parameters<typeof readSegment>[0];
export type RecursiveTupleA = [initial: string, next: RecursiveTupleA];
export type RecursiveTupleB = [first: string, ptr: RecursiveTupleB];
export type RecusiveRest = [first: string, ...rest: RecusiveRest[]];
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,258 @@
//// [tests/cases/compiler/verbatim-declarations-assertions.ts] ////

//// [assertToTypeReferences.ts]
type P = { } & { name: string }

export let vLet = null! as P
export const vConst = null! as P

export function fn(p = null! as P) {}

export function fnWithRequiredDefaultParam(p = null! as P, req: number) {}

export class C {
field = null! as P
readonly roFiled = null! as P;
method(p = null! as P) {}
methodWithRequiredDefault(p = null! as P, req: number) {}
methodWithRequiredDefault2(p = null! as P, req: number) {}

constructor(public ctorField = null! as P) {}
}

export default null! as P;

//// [assertToTypeLiteral.ts]
export let vLet = null! as {} & { name: string }
export const vConst = null! as {} & { name: string }

export function fn(p = null! as {} & { name: string }) {}

export function fnWithRequiredDefaultParam(p = null! as {} & { name: string }, req: number) {}

export class C {
field = null! as {} & { name: string }
readonly roFiled = null! as {} & { name: string };
method(p = null! as {} & { name: string }) {}
methodWithRequiredDefault(p = null! as {} & { name: string }, req: number) {}

constructor(public ctorField = null! as {} & { name: string }) {}

get x() { return null! as {} & { name: string } }
set x(v) { }
}

export default null! as {} & { name: string }


//// [assertToOtherTypes.ts]
export const vNumberLiteral = null! as 1 | 1
export const vStringLiteral = null! as "1" | "1"
export const vLiteral = null! as "1" | "1"

type R = { foo: string }

export class C {
// under !strictNullChecks all types can be reused from the assertion
// under strictNullChecks we need to add undefined, and we can't always know we can
// Can't know if references contain undefined, fall back to inference
tsResolve? = null! as R | R;
tsResolve2? = null! as R | R | string;
// Simple type. we can add undefined
reuseType? = null! as ((p: R) => void) | string | string;
reuseType2? = null! as (new (p: R) => R) | string | string;
reuseType3? = null! as string | number | bigint | symbol | unknown | any | never | symbol;
reuseType4? = null! as [R, R, R] | [R, R, R];
reuseType5? = null! as R[] | R[];
reuseType6? = null! as 1 | "2" | 1n | 1n;
reuseType7? = null! as `A` | `A`;
reuseType8? = null! as `${string}-ok` | `${string}-ok`;
reuseType9? = null! as this | this;
}

//// [assertToTypeReferences.js]
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.C = exports.fnWithRequiredDefaultParam = exports.fn = exports.vConst = exports.vLet = void 0;
exports.vLet = null;
exports.vConst = null;
function fn(p) {
if (p === void 0) { p = null; }
}
exports.fn = fn;
function fnWithRequiredDefaultParam(p, req) {
if (p === void 0) { p = null; }
}
exports.fnWithRequiredDefaultParam = fnWithRequiredDefaultParam;
var C = /** @class */ (function () {
function C(ctorField) {
if (ctorField === void 0) { ctorField = null; }
this.ctorField = ctorField;
this.field = null;
this.roFiled = null;
}
C.prototype.method = function (p) {
if (p === void 0) { p = null; }
};
C.prototype.methodWithRequiredDefault = function (p, req) {
if (p === void 0) { p = null; }
};
C.prototype.methodWithRequiredDefault2 = function (p, req) {
if (p === void 0) { p = null; }
};
return C;
}());
exports.C = C;
exports.default = null;
//// [assertToTypeLiteral.js]
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.C = exports.fnWithRequiredDefaultParam = exports.fn = exports.vConst = exports.vLet = void 0;
exports.vLet = null;
exports.vConst = null;
function fn(p) {
if (p === void 0) { p = null; }
}
exports.fn = fn;
function fnWithRequiredDefaultParam(p, req) {
if (p === void 0) { p = null; }
}
exports.fnWithRequiredDefaultParam = fnWithRequiredDefaultParam;
var C = /** @class */ (function () {
function C(ctorField) {
if (ctorField === void 0) { ctorField = null; }
this.ctorField = ctorField;
this.field = null;
this.roFiled = null;
}
C.prototype.method = function (p) {
if (p === void 0) { p = null; }
};
C.prototype.methodWithRequiredDefault = function (p, req) {
if (p === void 0) { p = null; }
};
Object.defineProperty(C.prototype, "x", {
get: function () { return null; },
set: function (v) { },
enumerable: false,
configurable: true
});
return C;
}());
exports.C = C;
exports.default = null;
//// [assertToOtherTypes.js]
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.C = exports.vLiteral = exports.vStringLiteral = exports.vNumberLiteral = void 0;
exports.vNumberLiteral = null;
exports.vStringLiteral = null;
exports.vLiteral = null;
var C = /** @class */ (function () {
function C() {
// under !strictNullChecks all types can be reused from the assertion
// under strictNullChecks we need to add undefined, and we can't always know we can
// Can't know if references contain undefined, fall back to inference
this.tsResolve = null;
this.tsResolve2 = null;
// Simple type. we can add undefined
this.reuseType = null;
this.reuseType2 = null;
this.reuseType3 = null;
this.reuseType4 = null;
this.reuseType5 = null;
this.reuseType6 = null;
this.reuseType7 = null;
this.reuseType8 = null;
this.reuseType9 = null;
}
return C;
}());
exports.C = C;


//// [assertToTypeReferences.d.ts]
type P = {} & {
name: string;
};
export declare let vLet: P;
export declare const vConst: P;
export declare function fn(p?: P): void;
export declare function fnWithRequiredDefaultParam(p: P, req: number): void;
export declare class C {
ctorField: P;
field: P;
readonly roFiled: P;
method(p?: P): void;
methodWithRequiredDefault(p: P, req: number): void;
methodWithRequiredDefault2(p: P, req: number): void;
constructor(ctorField?: P);
}
declare const _default: {
name: string;
};
export default _default;
//// [assertToTypeLiteral.d.ts]
export declare let vLet: {} & {
name: string;
};
export declare const vConst: {} & {
name: string;
};
export declare function fn(p?: {} & {
name: string;
}): void;
export declare function fnWithRequiredDefaultParam(p: {} & {
name: string;
}, req: number): void;
export declare class C {
ctorField: {} & {
name: string;
};
field: {} & {
name: string;
};
readonly roFiled: {} & {
name: string;
};
method(p?: {} & {
name: string;
}): void;
methodWithRequiredDefault(p: {} & {
name: string;
}, req: number): void;
constructor(ctorField?: {} & {
name: string;
});
get x(): {
name: string;
};
set x(v: {
name: string;
});
}
declare const _default: {
name: string;
};
export default _default;
//// [assertToOtherTypes.d.ts]
export declare const vNumberLiteral: 1 | 1;
export declare const vStringLiteral: "1" | "1";
export declare const vLiteral: "1" | "1";
type R = {
foo: string;
};
export declare class C {
tsResolve?: R | R;
tsResolve2?: R | R | string;
reuseType?: ((p: R) => void) | string | string;
reuseType2?: (new (p: R) => R) | string | string;
reuseType3?: string | number | bigint | symbol | unknown | any | never | symbol;
reuseType4?: [R, R, R] | [R, R, R];
reuseType5?: R[] | R[];
reuseType6?: 1 | "2" | 1n | 1n;
reuseType7?: `A` | `A`;
reuseType8?: `${string}-ok` | `${string}-ok`;
reuseType9?: this | this;
}
export {};