Skip to content

Commit e2436f3

Browse files
authored
Use constraint for default default value if possible (#28222)
1 parent 4cfff89 commit e2436f3

6 files changed

+70
-1
lines changed

src/compiler/checker.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7653,7 +7653,7 @@ namespace ts {
76537653
// If a type parameter does not have a default type, or if the default type
76547654
// is a forward reference, the empty object type is used.
76557655
for (let i = numTypeArguments; i < numTypeParameters; i++) {
7656-
result[i] = getDefaultTypeArgumentType(isJavaScriptImplicitAny);
7656+
result[i] = getConstraintFromTypeParameter(typeParameters![i]) || getDefaultTypeArgumentType(isJavaScriptImplicitAny);
76577657
}
76587658
for (let i = numTypeArguments; i < numTypeParameters; i++) {
76597659
const mapper = createTypeMapper(typeParameters!, result);
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
tests/cases/compiler/typeArgumentDefaultUsesConstraintOnCircularDefault.ts(3,18): error TS2322: Type '{ foo: string; }' is not assignable to type 'Test<string>'.
2+
Object literal may only specify known properties, and 'foo' does not exist in type 'Test<string>'.
3+
tests/cases/compiler/typeArgumentDefaultUsesConstraintOnCircularDefault.ts(5,19): error TS2322: Type '{}' is not assignable to type 'string'.
4+
5+
6+
==== tests/cases/compiler/typeArgumentDefaultUsesConstraintOnCircularDefault.ts (2 errors) ====
7+
type Test<T extends string = T> = { value: T };
8+
9+
let zz: Test = { foo: "abc" }; // should error on comparison with Test<string>
10+
~~~~~~~~~~
11+
!!! error TS2322: Type '{ foo: string; }' is not assignable to type 'Test<string>'.
12+
!!! error TS2322: Object literal may only specify known properties, and 'foo' does not exist in type 'Test<string>'.
13+
14+
let zzy: Test = { value: {} }; // should error
15+
~~~~~
16+
!!! error TS2322: Type '{}' is not assignable to type 'string'.
17+
!!! related TS6500 tests/cases/compiler/typeArgumentDefaultUsesConstraintOnCircularDefault.ts:1:37: The expected type comes from property 'value' which is declared here on type 'Test<string>'
18+
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
//// [typeArgumentDefaultUsesConstraintOnCircularDefault.ts]
2+
type Test<T extends string = T> = { value: T };
3+
4+
let zz: Test = { foo: "abc" }; // should error on comparison with Test<string>
5+
6+
let zzy: Test = { value: {} }; // should error
7+
8+
9+
//// [typeArgumentDefaultUsesConstraintOnCircularDefault.js]
10+
var zz = { foo: "abc" }; // should error on comparison with Test<string>
11+
var zzy = { value: {} }; // should error
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
=== tests/cases/compiler/typeArgumentDefaultUsesConstraintOnCircularDefault.ts ===
2+
type Test<T extends string = T> = { value: T };
3+
>Test : Symbol(Test, Decl(typeArgumentDefaultUsesConstraintOnCircularDefault.ts, 0, 0))
4+
>T : Symbol(T, Decl(typeArgumentDefaultUsesConstraintOnCircularDefault.ts, 0, 10))
5+
>T : Symbol(T, Decl(typeArgumentDefaultUsesConstraintOnCircularDefault.ts, 0, 10))
6+
>value : Symbol(value, Decl(typeArgumentDefaultUsesConstraintOnCircularDefault.ts, 0, 35))
7+
>T : Symbol(T, Decl(typeArgumentDefaultUsesConstraintOnCircularDefault.ts, 0, 10))
8+
9+
let zz: Test = { foo: "abc" }; // should error on comparison with Test<string>
10+
>zz : Symbol(zz, Decl(typeArgumentDefaultUsesConstraintOnCircularDefault.ts, 2, 3))
11+
>Test : Symbol(Test, Decl(typeArgumentDefaultUsesConstraintOnCircularDefault.ts, 0, 0))
12+
>foo : Symbol(foo, Decl(typeArgumentDefaultUsesConstraintOnCircularDefault.ts, 2, 16))
13+
14+
let zzy: Test = { value: {} }; // should error
15+
>zzy : Symbol(zzy, Decl(typeArgumentDefaultUsesConstraintOnCircularDefault.ts, 4, 3))
16+
>Test : Symbol(Test, Decl(typeArgumentDefaultUsesConstraintOnCircularDefault.ts, 0, 0))
17+
>value : Symbol(value, Decl(typeArgumentDefaultUsesConstraintOnCircularDefault.ts, 4, 17))
18+
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
=== tests/cases/compiler/typeArgumentDefaultUsesConstraintOnCircularDefault.ts ===
2+
type Test<T extends string = T> = { value: T };
3+
>Test : Test<T>
4+
>value : T
5+
6+
let zz: Test = { foo: "abc" }; // should error on comparison with Test<string>
7+
>zz : Test<string>
8+
>{ foo: "abc" } : { foo: string; }
9+
>foo : string
10+
>"abc" : "abc"
11+
12+
let zzy: Test = { value: {} }; // should error
13+
>zzy : Test<string>
14+
>{ value: {} } : { value: {}; }
15+
>value : {}
16+
>{} : {}
17+
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
type Test<T extends string = T> = { value: T };
2+
3+
let zz: Test = { foo: "abc" }; // should error on comparison with Test<string>
4+
5+
let zzy: Test = { value: {} }; // should error

0 commit comments

Comments
 (0)