Skip to content

Commit b82fd16

Browse files
🤖 Pick PR #60576 (Avoid incorrectly reusing assertion...) into release-5.7 (#60679)
Co-authored-by: Mateusz Burzyński <mateuszburzynski@gmail.com>
1 parent 2d11280 commit b82fd16

6 files changed

+252
-3
lines changed

‎src/compiler/expressionToTypeNode.ts

+3-3
Original file line numberDiff line numberDiff line change
@@ -706,12 +706,12 @@ export function createSyntacticTypeNodeBuilder(
706706
}
707707
if (!result && node.kind === SyntaxKind.PropertyAssignment) {
708708
const initializer = node.initializer;
709-
const type = isJSDocTypeAssertion(initializer) ? getJSDocTypeAssertionType(initializer) :
709+
const assertionNode = isJSDocTypeAssertion(initializer) ? getJSDocTypeAssertionType(initializer) :
710710
initializer.kind === SyntaxKind.AsExpression || initializer.kind === SyntaxKind.TypeAssertionExpression ? (initializer as AsExpression | TypeAssertion).type :
711711
undefined;
712712

713-
if (type && !isConstTypeReference(type)) {
714-
result = serializeExistingTypeNode(type, context);
713+
if (assertionNode && !isConstTypeReference(assertionNode) && resolver.canReuseTypeNodeAnnotation(context, node, assertionNode, symbol)) {
714+
result = serializeExistingTypeNode(assertionNode, context);
715715
}
716716
}
717717
return result ?? inferTypeOfDeclaration(node, symbol, context, /*reportFallback*/ false);
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
//// [tests/cases/compiler/declarationAssertionNodeNotReusedWhenTypeNotEquivalent1.ts] ////
2+
3+
//// [declarationAssertionNodeNotReusedWhenTypeNotEquivalent1.ts]
4+
type Wrapper<T> = {
5+
_type: T;
6+
};
7+
8+
declare function stringWrapper(): Wrapper<string>;
9+
10+
declare function objWrapper<T extends Record<string, Wrapper<any>>>(
11+
obj: T,
12+
): Wrapper<T>;
13+
14+
const value = objWrapper({
15+
prop1: stringWrapper() as Wrapper<"hello">,
16+
});
17+
18+
type Unwrap<T> = T extends Wrapper<any>
19+
? T["_type"] extends Record<string, Wrapper<any>>
20+
? { [Key in keyof T["_type"]]: Unwrap<T["_type"][Key]> }
21+
: T["_type"]
22+
: never;
23+
24+
declare function unwrap<T>(wrapper: T): Unwrap<T>;
25+
26+
export const unwrapped = unwrap(value);
27+
28+
29+
30+
31+
//// [declarationAssertionNodeNotReusedWhenTypeNotEquivalent1.d.ts]
32+
export declare const unwrapped: {
33+
prop1: "hello";
34+
};
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
//// [tests/cases/compiler/declarationAssertionNodeNotReusedWhenTypeNotEquivalent1.ts] ////
2+
3+
=== declarationAssertionNodeNotReusedWhenTypeNotEquivalent1.ts ===
4+
type Wrapper<T> = {
5+
>Wrapper : Symbol(Wrapper, Decl(declarationAssertionNodeNotReusedWhenTypeNotEquivalent1.ts, 0, 0))
6+
>T : Symbol(T, Decl(declarationAssertionNodeNotReusedWhenTypeNotEquivalent1.ts, 0, 13))
7+
8+
_type: T;
9+
>_type : Symbol(_type, Decl(declarationAssertionNodeNotReusedWhenTypeNotEquivalent1.ts, 0, 19))
10+
>T : Symbol(T, Decl(declarationAssertionNodeNotReusedWhenTypeNotEquivalent1.ts, 0, 13))
11+
12+
};
13+
14+
declare function stringWrapper(): Wrapper<string>;
15+
>stringWrapper : Symbol(stringWrapper, Decl(declarationAssertionNodeNotReusedWhenTypeNotEquivalent1.ts, 2, 2))
16+
>Wrapper : Symbol(Wrapper, Decl(declarationAssertionNodeNotReusedWhenTypeNotEquivalent1.ts, 0, 0))
17+
18+
declare function objWrapper<T extends Record<string, Wrapper<any>>>(
19+
>objWrapper : Symbol(objWrapper, Decl(declarationAssertionNodeNotReusedWhenTypeNotEquivalent1.ts, 4, 50))
20+
>T : Symbol(T, Decl(declarationAssertionNodeNotReusedWhenTypeNotEquivalent1.ts, 6, 28))
21+
>Record : Symbol(Record, Decl(lib.es5.d.ts, --, --))
22+
>Wrapper : Symbol(Wrapper, Decl(declarationAssertionNodeNotReusedWhenTypeNotEquivalent1.ts, 0, 0))
23+
24+
obj: T,
25+
>obj : Symbol(obj, Decl(declarationAssertionNodeNotReusedWhenTypeNotEquivalent1.ts, 6, 68))
26+
>T : Symbol(T, Decl(declarationAssertionNodeNotReusedWhenTypeNotEquivalent1.ts, 6, 28))
27+
28+
): Wrapper<T>;
29+
>Wrapper : Symbol(Wrapper, Decl(declarationAssertionNodeNotReusedWhenTypeNotEquivalent1.ts, 0, 0))
30+
>T : Symbol(T, Decl(declarationAssertionNodeNotReusedWhenTypeNotEquivalent1.ts, 6, 28))
31+
32+
const value = objWrapper({
33+
>value : Symbol(value, Decl(declarationAssertionNodeNotReusedWhenTypeNotEquivalent1.ts, 10, 5))
34+
>objWrapper : Symbol(objWrapper, Decl(declarationAssertionNodeNotReusedWhenTypeNotEquivalent1.ts, 4, 50))
35+
36+
prop1: stringWrapper() as Wrapper<"hello">,
37+
>prop1 : Symbol(prop1, Decl(declarationAssertionNodeNotReusedWhenTypeNotEquivalent1.ts, 10, 26))
38+
>stringWrapper : Symbol(stringWrapper, Decl(declarationAssertionNodeNotReusedWhenTypeNotEquivalent1.ts, 2, 2))
39+
>Wrapper : Symbol(Wrapper, Decl(declarationAssertionNodeNotReusedWhenTypeNotEquivalent1.ts, 0, 0))
40+
41+
});
42+
43+
type Unwrap<T> = T extends Wrapper<any>
44+
>Unwrap : Symbol(Unwrap, Decl(declarationAssertionNodeNotReusedWhenTypeNotEquivalent1.ts, 12, 3))
45+
>T : Symbol(T, Decl(declarationAssertionNodeNotReusedWhenTypeNotEquivalent1.ts, 14, 12))
46+
>T : Symbol(T, Decl(declarationAssertionNodeNotReusedWhenTypeNotEquivalent1.ts, 14, 12))
47+
>Wrapper : Symbol(Wrapper, Decl(declarationAssertionNodeNotReusedWhenTypeNotEquivalent1.ts, 0, 0))
48+
49+
? T["_type"] extends Record<string, Wrapper<any>>
50+
>T : Symbol(T, Decl(declarationAssertionNodeNotReusedWhenTypeNotEquivalent1.ts, 14, 12))
51+
>Record : Symbol(Record, Decl(lib.es5.d.ts, --, --))
52+
>Wrapper : Symbol(Wrapper, Decl(declarationAssertionNodeNotReusedWhenTypeNotEquivalent1.ts, 0, 0))
53+
54+
? { [Key in keyof T["_type"]]: Unwrap<T["_type"][Key]> }
55+
>Key : Symbol(Key, Decl(declarationAssertionNodeNotReusedWhenTypeNotEquivalent1.ts, 16, 9))
56+
>T : Symbol(T, Decl(declarationAssertionNodeNotReusedWhenTypeNotEquivalent1.ts, 14, 12))
57+
>Unwrap : Symbol(Unwrap, Decl(declarationAssertionNodeNotReusedWhenTypeNotEquivalent1.ts, 12, 3))
58+
>T : Symbol(T, Decl(declarationAssertionNodeNotReusedWhenTypeNotEquivalent1.ts, 14, 12))
59+
>Key : Symbol(Key, Decl(declarationAssertionNodeNotReusedWhenTypeNotEquivalent1.ts, 16, 9))
60+
61+
: T["_type"]
62+
>T : Symbol(T, Decl(declarationAssertionNodeNotReusedWhenTypeNotEquivalent1.ts, 14, 12))
63+
64+
: never;
65+
66+
declare function unwrap<T>(wrapper: T): Unwrap<T>;
67+
>unwrap : Symbol(unwrap, Decl(declarationAssertionNodeNotReusedWhenTypeNotEquivalent1.ts, 18, 10))
68+
>T : Symbol(T, Decl(declarationAssertionNodeNotReusedWhenTypeNotEquivalent1.ts, 20, 24))
69+
>wrapper : Symbol(wrapper, Decl(declarationAssertionNodeNotReusedWhenTypeNotEquivalent1.ts, 20, 27))
70+
>T : Symbol(T, Decl(declarationAssertionNodeNotReusedWhenTypeNotEquivalent1.ts, 20, 24))
71+
>Unwrap : Symbol(Unwrap, Decl(declarationAssertionNodeNotReusedWhenTypeNotEquivalent1.ts, 12, 3))
72+
>T : Symbol(T, Decl(declarationAssertionNodeNotReusedWhenTypeNotEquivalent1.ts, 20, 24))
73+
74+
export const unwrapped = unwrap(value);
75+
>unwrapped : Symbol(unwrapped, Decl(declarationAssertionNodeNotReusedWhenTypeNotEquivalent1.ts, 22, 12))
76+
>unwrap : Symbol(unwrap, Decl(declarationAssertionNodeNotReusedWhenTypeNotEquivalent1.ts, 18, 10))
77+
>value : Symbol(value, Decl(declarationAssertionNodeNotReusedWhenTypeNotEquivalent1.ts, 10, 5))
78+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
//// [tests/cases/compiler/declarationAssertionNodeNotReusedWhenTypeNotEquivalent1.ts] ////
2+
3+
=== declarationAssertionNodeNotReusedWhenTypeNotEquivalent1.ts ===
4+
type Wrapper<T> = {
5+
>Wrapper : Wrapper<T>
6+
> : ^^^^^^^^^^
7+
8+
_type: T;
9+
>_type : T
10+
> : ^
11+
12+
};
13+
14+
declare function stringWrapper(): Wrapper<string>;
15+
>stringWrapper : () => Wrapper<string>
16+
> : ^^^^^^
17+
18+
declare function objWrapper<T extends Record<string, Wrapper<any>>>(
19+
>objWrapper : <T extends Record<string, Wrapper<any>>>(obj: T) => Wrapper<T>
20+
> : ^ ^^^^^^^^^ ^^ ^^ ^^^^^
21+
22+
obj: T,
23+
>obj : T
24+
> : ^
25+
26+
): Wrapper<T>;
27+
28+
const value = objWrapper({
29+
>value : Wrapper<{ prop1: Wrapper<"hello">; }>
30+
> : ^^^^^^^^^^^^^^^^^ ^^^^
31+
>objWrapper({ prop1: stringWrapper() as Wrapper<"hello">,}) : Wrapper<{ prop1: Wrapper<"hello">; }>
32+
> : ^^^^^^^^^^^^^^^^^ ^^^^
33+
>objWrapper : <T extends Record<string, Wrapper<any>>>(obj: T) => Wrapper<T>
34+
> : ^ ^^^^^^^^^ ^^ ^^ ^^^^^
35+
>{ prop1: stringWrapper() as Wrapper<"hello">,} : { prop1: Wrapper<"hello">; }
36+
> : ^^^^^^^^^ ^^^
37+
38+
prop1: stringWrapper() as Wrapper<"hello">,
39+
>prop1 : Wrapper<"hello">
40+
> : ^^^^^^^^^^^^^^^^
41+
>stringWrapper() as Wrapper<"hello"> : Wrapper<"hello">
42+
> : ^^^^^^^^^^^^^^^^
43+
>stringWrapper() : Wrapper<string>
44+
> : ^^^^^^^^^^^^^^^
45+
>stringWrapper : () => Wrapper<string>
46+
> : ^^^^^^
47+
48+
});
49+
50+
type Unwrap<T> = T extends Wrapper<any>
51+
>Unwrap : Unwrap<T>
52+
> : ^^^^^^^^^
53+
54+
? T["_type"] extends Record<string, Wrapper<any>>
55+
? { [Key in keyof T["_type"]]: Unwrap<T["_type"][Key]> }
56+
: T["_type"]
57+
: never;
58+
59+
declare function unwrap<T>(wrapper: T): Unwrap<T>;
60+
>unwrap : <T>(wrapper: T) => Unwrap<T>
61+
> : ^ ^^ ^^ ^^^^^
62+
>wrapper : T
63+
> : ^
64+
65+
export const unwrapped = unwrap(value);
66+
>unwrapped : { prop1: "hello"; }
67+
> : ^^^^^^^^^^^^^^^^^^^
68+
>unwrap(value) : { prop1: "hello"; }
69+
> : ^^^^^^^^^^^^^^^^^^^
70+
>unwrap : <T>(wrapper: T) => Unwrap<T>
71+
> : ^ ^^ ^^ ^^^^^
72+
>value : Wrapper<{ prop1: Wrapper<"hello">; }>
73+
> : ^^^^^^^^^^^^^^^^^ ^^^^
74+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
// @strict: true
2+
// @declaration: true
3+
// @emitDeclarationOnly: true
4+
5+
type Wrapper<T> = {
6+
_type: T;
7+
};
8+
9+
declare function stringWrapper(): Wrapper<string>;
10+
11+
declare function objWrapper<T extends Record<string, Wrapper<any>>>(
12+
obj: T,
13+
): Wrapper<T>;
14+
15+
const value = objWrapper({
16+
prop1: stringWrapper() as Wrapper<"hello">,
17+
});
18+
19+
type Unwrap<T> = T extends Wrapper<any>
20+
? T["_type"] extends Record<string, Wrapper<any>>
21+
? { [Key in keyof T["_type"]]: Unwrap<T["_type"][Key]> }
22+
: T["_type"]
23+
: never;
24+
25+
declare function unwrap<T>(wrapper: T): Unwrap<T>;
26+
27+
export const unwrapped = unwrap(value);
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
/// <reference path="fourslash.ts" />
2+
3+
// https://github.com/microsoft/TypeScript/issues/60573
4+
5+
// @strict: true
6+
7+
//// type Wrapper<T> = {
8+
//// _type: T;
9+
//// };
10+
////
11+
//// function stringWrapper(): Wrapper<string> {
12+
//// return { _type: "" };
13+
//// }
14+
////
15+
//// function objWrapper<T extends Record<string, Wrapper<any>>>(
16+
//// obj: T,
17+
//// ): Wrapper<T> {
18+
//// return { _type: obj };
19+
//// }
20+
////
21+
//// const value = objWrapper({
22+
//// prop1: stringWrapper() as Wrapper<"hello">,
23+
//// });
24+
////
25+
//// type Unwrap<T extends Wrapper<any>> = T["_type"] extends Record<
26+
//// string,
27+
//// Wrapper<any>
28+
//// >
29+
//// ? { [Key in keyof T["_type"]]: Unwrap<T["_type"][Key]> }
30+
//// : T["_type"];
31+
////
32+
//// type Test/*1*/ = Unwrap<typeof value>;
33+
34+
verify.quickInfoAt("1", `type Test = {
35+
prop1: "hello";
36+
}`)

0 commit comments

Comments
 (0)