Skip to content

Commit 67c6ceb

Browse files
weswighamsandersn
andauthored
Reinterpret a type parameter constrained to any as an upper bound constraint (#29571)
* Reinterpret a type parameter constrained to any as an upper bound constraint * Use real constraqint in alias in test Co-authored-by: Nathan Shively-Sanders <[email protected]>
1 parent 3fdce8e commit 67c6ceb

21 files changed

+254
-36
lines changed

src/compiler/checker.ts

+12-2
Original file line numberDiff line numberDiff line change
@@ -11058,8 +11058,18 @@ namespace ts {
1105811058
}
1105911059
else {
1106011060
const constraintDeclaration = getConstraintDeclaration(typeParameter);
11061-
typeParameter.constraint = constraintDeclaration ? getTypeFromTypeNode(constraintDeclaration) :
11062-
getInferredTypeParameterConstraint(typeParameter) || noConstraintType;
11061+
if (!constraintDeclaration) {
11062+
typeParameter.constraint = getInferredTypeParameterConstraint(typeParameter) || noConstraintType;
11063+
}
11064+
else {
11065+
let type = getTypeFromTypeNode(constraintDeclaration);
11066+
if (type.flags & TypeFlags.Any && type !== errorType) { // Allow errorType to propegate to keep downstream errors suppressed
11067+
// use keyofConstraintType as the base constraint for mapped type key constraints (unknown isn;t assignable to that, but `any` was),
11068+
// use unknown otherwise
11069+
type = constraintDeclaration.parent.parent.kind === SyntaxKind.MappedType ? keyofConstraintType : unknownType;
11070+
}
11071+
typeParameter.constraint = type;
11072+
}
1106311073
}
1106411074
}
1106511075
return typeParameter.constraint === noConstraintType ? undefined : typeParameter.constraint;

tests/baselines/reference/contextuallyTypedParametersWithInitializers.types

+2-2
Original file line numberDiff line numberDiff line change
@@ -162,7 +162,7 @@ declare function g1<T>(x: T): T;
162162
>x : T
163163

164164
declare function g2<T extends any>(x: T): T;
165-
>g2 : <T extends any>(x: T) => T
165+
>g2 : <T extends unknown>(x: T) => T
166166
>x : T
167167

168168
declare function g3<T extends unknown>(x: T): T;
@@ -192,7 +192,7 @@ g1((x = 1) => 0); // number
192192

193193
g2((x = 1) => 0); // number
194194
>g2((x = 1) => 0) : (x?: number) => 0
195-
>g2 : <T extends any>(x: T) => T
195+
>g2 : <T extends unknown>(x: T) => T
196196
>(x = 1) => 0 : (x?: number) => 0
197197
>x : number
198198
>1 : 1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
tests/cases/compiler/jsxExcessPropsAndAssignability.tsx(16,6): error TS2322: Type 'ComposedComponentProps & { myProp: number; }' is not assignable to type 'IntrinsicAttributes & IntrinsicClassAttributes<Component<WrapperComponentProps, any, any>> & Readonly<{ children?: ReactNode; }> & Readonly<WrapperComponentProps>'.
2+
Type 'ComposedComponentProps & { myProp: number; }' is not assignable to type 'Readonly<WrapperComponentProps>'.
3+
4+
5+
==== tests/cases/compiler/jsxExcessPropsAndAssignability.tsx (1 errors) ====
6+
/// <reference path="/.lib/react16.d.ts" />
7+
8+
import * as React from 'react';
9+
10+
const myHoc = <ComposedComponentProps extends any>(
11+
ComposedComponent: React.ComponentClass<ComposedComponentProps>,
12+
) => {
13+
type WrapperComponentProps = ComposedComponentProps & { myProp: string };
14+
const WrapperComponent: React.ComponentClass<WrapperComponentProps> = null as any;
15+
16+
const props: ComposedComponentProps = null as any;
17+
18+
// Expected no error, got none - good
19+
<WrapperComponent {...props} myProp={'1000000'} />;
20+
// Expected error, but got none - bad!
21+
<WrapperComponent {...props} myProp={1000000} />;
22+
~~~~~~~~~~~~~~~~
23+
!!! error TS2322: Type 'ComposedComponentProps & { myProp: number; }' is not assignable to type 'IntrinsicAttributes & IntrinsicClassAttributes<Component<WrapperComponentProps, any, any>> & Readonly<{ children?: ReactNode; }> & Readonly<WrapperComponentProps>'.
24+
!!! error TS2322: Type 'ComposedComponentProps & { myProp: number; }' is not assignable to type 'Readonly<WrapperComponentProps>'.
25+
};
26+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
//// [jsxExcessPropsAndAssignability.tsx]
2+
/// <reference path="/.lib/react16.d.ts" />
3+
4+
import * as React from 'react';
5+
6+
const myHoc = <ComposedComponentProps extends any>(
7+
ComposedComponent: React.ComponentClass<ComposedComponentProps>,
8+
) => {
9+
type WrapperComponentProps = ComposedComponentProps & { myProp: string };
10+
const WrapperComponent: React.ComponentClass<WrapperComponentProps> = null as any;
11+
12+
const props: ComposedComponentProps = null as any;
13+
14+
// Expected no error, got none - good
15+
<WrapperComponent {...props} myProp={'1000000'} />;
16+
// Expected error, but got none - bad!
17+
<WrapperComponent {...props} myProp={1000000} />;
18+
};
19+
20+
21+
//// [jsxExcessPropsAndAssignability.js]
22+
"use strict";
23+
/// <reference path="react16.d.ts" />
24+
var __assign = (this && this.__assign) || function () {
25+
__assign = Object.assign || function(t) {
26+
for (var s, i = 1, n = arguments.length; i < n; i++) {
27+
s = arguments[i];
28+
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
29+
t[p] = s[p];
30+
}
31+
return t;
32+
};
33+
return __assign.apply(this, arguments);
34+
};
35+
exports.__esModule = true;
36+
var React = require("react");
37+
var myHoc = function (ComposedComponent) {
38+
var WrapperComponent = null;
39+
var props = null;
40+
// Expected no error, got none - good
41+
React.createElement(WrapperComponent, __assign({}, props, { myProp: '1000000' }));
42+
// Expected error, but got none - bad!
43+
React.createElement(WrapperComponent, __assign({}, props, { myProp: 1000000 }));
44+
};
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
=== tests/cases/compiler/jsxExcessPropsAndAssignability.tsx ===
2+
/// <reference path="react16.d.ts" />
3+
4+
import * as React from 'react';
5+
>React : Symbol(React, Decl(jsxExcessPropsAndAssignability.tsx, 2, 6))
6+
7+
const myHoc = <ComposedComponentProps extends any>(
8+
>myHoc : Symbol(myHoc, Decl(jsxExcessPropsAndAssignability.tsx, 4, 5))
9+
>ComposedComponentProps : Symbol(ComposedComponentProps, Decl(jsxExcessPropsAndAssignability.tsx, 4, 15))
10+
11+
ComposedComponent: React.ComponentClass<ComposedComponentProps>,
12+
>ComposedComponent : Symbol(ComposedComponent, Decl(jsxExcessPropsAndAssignability.tsx, 4, 51))
13+
>React : Symbol(React, Decl(jsxExcessPropsAndAssignability.tsx, 2, 6))
14+
>ComponentClass : Symbol(React.ComponentClass, Decl(react16.d.ts, 421, 9))
15+
>ComposedComponentProps : Symbol(ComposedComponentProps, Decl(jsxExcessPropsAndAssignability.tsx, 4, 15))
16+
17+
) => {
18+
type WrapperComponentProps = ComposedComponentProps & { myProp: string };
19+
>WrapperComponentProps : Symbol(WrapperComponentProps, Decl(jsxExcessPropsAndAssignability.tsx, 6, 6))
20+
>ComposedComponentProps : Symbol(ComposedComponentProps, Decl(jsxExcessPropsAndAssignability.tsx, 4, 15))
21+
>myProp : Symbol(myProp, Decl(jsxExcessPropsAndAssignability.tsx, 7, 59))
22+
23+
const WrapperComponent: React.ComponentClass<WrapperComponentProps> = null as any;
24+
>WrapperComponent : Symbol(WrapperComponent, Decl(jsxExcessPropsAndAssignability.tsx, 8, 9))
25+
>React : Symbol(React, Decl(jsxExcessPropsAndAssignability.tsx, 2, 6))
26+
>ComponentClass : Symbol(React.ComponentClass, Decl(react16.d.ts, 421, 9))
27+
>WrapperComponentProps : Symbol(WrapperComponentProps, Decl(jsxExcessPropsAndAssignability.tsx, 6, 6))
28+
29+
const props: ComposedComponentProps = null as any;
30+
>props : Symbol(props, Decl(jsxExcessPropsAndAssignability.tsx, 10, 9))
31+
>ComposedComponentProps : Symbol(ComposedComponentProps, Decl(jsxExcessPropsAndAssignability.tsx, 4, 15))
32+
33+
// Expected no error, got none - good
34+
<WrapperComponent {...props} myProp={'1000000'} />;
35+
>WrapperComponent : Symbol(WrapperComponent, Decl(jsxExcessPropsAndAssignability.tsx, 8, 9))
36+
>props : Symbol(props, Decl(jsxExcessPropsAndAssignability.tsx, 10, 9))
37+
>myProp : Symbol(myProp, Decl(jsxExcessPropsAndAssignability.tsx, 13, 32))
38+
39+
// Expected error, but got none - bad!
40+
<WrapperComponent {...props} myProp={1000000} />;
41+
>WrapperComponent : Symbol(WrapperComponent, Decl(jsxExcessPropsAndAssignability.tsx, 8, 9))
42+
>props : Symbol(props, Decl(jsxExcessPropsAndAssignability.tsx, 10, 9))
43+
>myProp : Symbol(myProp, Decl(jsxExcessPropsAndAssignability.tsx, 15, 32))
44+
45+
};
46+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
=== tests/cases/compiler/jsxExcessPropsAndAssignability.tsx ===
2+
/// <reference path="react16.d.ts" />
3+
4+
import * as React from 'react';
5+
>React : typeof React
6+
7+
const myHoc = <ComposedComponentProps extends any>(
8+
>myHoc : <ComposedComponentProps extends unknown>(ComposedComponent: React.ComponentClass<ComposedComponentProps, any>) => void
9+
><ComposedComponentProps extends any>( ComposedComponent: React.ComponentClass<ComposedComponentProps>,) => { type WrapperComponentProps = ComposedComponentProps & { myProp: string }; const WrapperComponent: React.ComponentClass<WrapperComponentProps> = null as any; const props: ComposedComponentProps = null as any; // Expected no error, got none - good <WrapperComponent {...props} myProp={'1000000'} />; // Expected error, but got none - bad! <WrapperComponent {...props} myProp={1000000} />;} : <ComposedComponentProps extends unknown>(ComposedComponent: React.ComponentClass<ComposedComponentProps, any>) => void
10+
11+
ComposedComponent: React.ComponentClass<ComposedComponentProps>,
12+
>ComposedComponent : React.ComponentClass<ComposedComponentProps, any>
13+
>React : any
14+
15+
) => {
16+
type WrapperComponentProps = ComposedComponentProps & { myProp: string };
17+
>WrapperComponentProps : ComposedComponentProps & { myProp: string; }
18+
>myProp : string
19+
20+
const WrapperComponent: React.ComponentClass<WrapperComponentProps> = null as any;
21+
>WrapperComponent : React.ComponentClass<ComposedComponentProps & { myProp: string; }, any>
22+
>React : any
23+
>null as any : any
24+
>null : null
25+
26+
const props: ComposedComponentProps = null as any;
27+
>props : ComposedComponentProps
28+
>null as any : any
29+
>null : null
30+
31+
// Expected no error, got none - good
32+
<WrapperComponent {...props} myProp={'1000000'} />;
33+
><WrapperComponent {...props} myProp={'1000000'} /> : JSX.Element
34+
>WrapperComponent : React.ComponentClass<ComposedComponentProps & { myProp: string; }, any>
35+
>props : ComposedComponentProps
36+
>myProp : "1000000"
37+
>'1000000' : "1000000"
38+
39+
// Expected error, but got none - bad!
40+
<WrapperComponent {...props} myProp={1000000} />;
41+
><WrapperComponent {...props} myProp={1000000} /> : JSX.Element
42+
>WrapperComponent : React.ComponentClass<ComposedComponentProps & { myProp: string; }, any>
43+
>props : ComposedComponentProps
44+
>myProp : number
45+
>1000000 : 1000000
46+
47+
};
48+

tests/baselines/reference/mappedTypeWithAny.types

+1-1
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ declare let x0: keyof any;
1010
>x0 : string | number | symbol
1111

1212
declare let x1: { [P in any]: Item };
13-
>x1 : { [x: string]: Item; }
13+
>x1 : { [x: string]: Item; [x: number]: Item; }
1414

1515
declare let x2: { [P in string]: Item };
1616
>x2 : { [x: string]: Item; }

tests/baselines/reference/typeArgumentInferenceWithConstraints.types

+8-8
Original file line numberDiff line numberDiff line change
@@ -357,7 +357,7 @@ x<string, string, string>(null, null, null); // Error
357357

358358
// Generic call with multiple parameters of generic type passed arguments with no best common type
359359
function someGenerics9<T extends any>(a: T, b: T, c: T): T {
360-
>someGenerics9 : <T extends any>(a: T, b: T, c: T) => T
360+
>someGenerics9 : <T extends unknown>(a: T, b: T, c: T) => T
361361
>a : T
362362
>b : T
363363
>c : T
@@ -368,7 +368,7 @@ function someGenerics9<T extends any>(a: T, b: T, c: T): T {
368368
var a9a = someGenerics9('', 0, []);
369369
>a9a : string
370370
>someGenerics9('', 0, []) : ""
371-
>someGenerics9 : <T extends any>(a: T, b: T, c: T) => T
371+
>someGenerics9 : <T extends unknown>(a: T, b: T, c: T) => T
372372
>'' : ""
373373
>0 : 0
374374
>[] : undefined[]
@@ -379,7 +379,7 @@ var a9a: {};
379379
var a9b = someGenerics9<{ a?: number; b?: string; }>({ a: 0 }, { b: '' }, null);
380380
>a9b : { a?: number; b?: string; }
381381
>someGenerics9<{ a?: number; b?: string; }>({ a: 0 }, { b: '' }, null) : { a?: number; b?: string; }
382-
>someGenerics9 : <T extends any>(a: T, b: T, c: T) => T
382+
>someGenerics9 : <T extends unknown>(a: T, b: T, c: T) => T
383383
>a : number
384384
>b : string
385385
>{ a: 0 } : { a: number; }
@@ -413,7 +413,7 @@ interface A92 {
413413
var a9e = someGenerics9(undefined, { x: 6, z: window }, { x: 6, y: '' });
414414
>a9e : { x: number; z: Window & typeof globalThis; y?: undefined; } | { x: number; y: string; z?: undefined; }
415415
>someGenerics9(undefined, { x: 6, z: window }, { x: 6, y: '' }) : { x: number; z: Window & typeof globalThis; y?: undefined; } | { x: number; y: string; z?: undefined; }
416-
>someGenerics9 : <T extends any>(a: T, b: T, c: T) => T
416+
>someGenerics9 : <T extends unknown>(a: T, b: T, c: T) => T
417417
>undefined : undefined
418418
>{ x: 6, z: window } : { x: number; z: Window & typeof globalThis; }
419419
>x : number
@@ -432,7 +432,7 @@ var a9e: {};
432432
var a9f = someGenerics9<A92>(undefined, { x: 6, z: window }, { x: 6, y: '' });
433433
>a9f : A92
434434
>someGenerics9<A92>(undefined, { x: 6, z: window }, { x: 6, y: '' }) : A92
435-
>someGenerics9 : <T extends any>(a: T, b: T, c: T) => T
435+
>someGenerics9 : <T extends unknown>(a: T, b: T, c: T) => T
436436
>undefined : undefined
437437
>{ x: 6, z: window } : { x: number; z: Window & typeof globalThis; }
438438
>x : number
@@ -452,7 +452,7 @@ var a9f: A92;
452452
var a9d = someGenerics9({ x: 3 }, { x: 6 }, { x: 6 });
453453
>a9d : { x: number; }
454454
>someGenerics9({ x: 3 }, { x: 6 }, { x: 6 }) : { x: number; }
455-
>someGenerics9 : <T extends any>(a: T, b: T, c: T) => T
455+
>someGenerics9 : <T extends unknown>(a: T, b: T, c: T) => T
456456
>{ x: 3 } : { x: number; }
457457
>x : number
458458
>3 : 3
@@ -474,7 +474,7 @@ var anyVar: any;
474474
var a = someGenerics9(7, anyVar, 4);
475475
>a : any
476476
>someGenerics9(7, anyVar, 4) : any
477-
>someGenerics9 : <T extends any>(a: T, b: T, c: T) => T
477+
>someGenerics9 : <T extends unknown>(a: T, b: T, c: T) => T
478478
>7 : 7
479479
>anyVar : any
480480
>4 : 4
@@ -486,7 +486,7 @@ var a: any;
486486
var arr = someGenerics9([], null, undefined);
487487
>arr : any[]
488488
>someGenerics9([], null, undefined) : any[]
489-
>someGenerics9 : <T extends any>(a: T, b: T, c: T) => T
489+
>someGenerics9 : <T extends unknown>(a: T, b: T, c: T) => T
490490
>[] : undefined[]
491491
>null : null
492492
>undefined : undefined

tests/baselines/reference/typeParameterConstraints1.types

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
=== tests/cases/compiler/typeParameterConstraints1.ts ===
22
function foo1<T extends any>(test: T) { }
3-
>foo1 : <T extends any>(test: T) => void
3+
>foo1 : <T extends unknown>(test: T) => void
44
>test : T
55

66
function foo2<T extends number>(test: T) { }

tests/baselines/reference/typeParameterExplicitlyExtendsAny.errors.txt

+20-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,14 @@
11
tests/cases/compiler/typeParameterExplicitlyExtendsAny.ts(3,7): error TS2339: Property 'blah' does not exist on type 'T'.
2+
tests/cases/compiler/typeParameterExplicitlyExtendsAny.ts(9,7): error TS2339: Property 'blah' does not exist on type 'T'.
3+
tests/cases/compiler/typeParameterExplicitlyExtendsAny.ts(14,7): error TS2339: Property 'children' does not exist on type 'T'.
4+
tests/cases/compiler/typeParameterExplicitlyExtendsAny.ts(15,5): error TS2349: This expression is not callable.
5+
Type '{}' has no call signatures.
6+
tests/cases/compiler/typeParameterExplicitlyExtendsAny.ts(16,9): error TS2351: This expression is not constructable.
7+
Type '{}' has no construct signatures.
8+
tests/cases/compiler/typeParameterExplicitlyExtendsAny.ts(30,14): error TS2339: Property 'children' does not exist on type 'T'.
29

310

4-
==== tests/cases/compiler/typeParameterExplicitlyExtendsAny.ts (1 errors) ====
11+
==== tests/cases/compiler/typeParameterExplicitlyExtendsAny.ts (6 errors) ====
512
function fee<T>() {
613
var t: T;
714
t.blah; // Error
@@ -13,13 +20,23 @@ tests/cases/compiler/typeParameterExplicitlyExtendsAny.ts(3,7): error TS2339: Pr
1320
function fee2<T extends any>() {
1421
var t: T;
1522
t.blah; // ok
23+
~~~~
24+
!!! error TS2339: Property 'blah' does not exist on type 'T'.
1625
t.toString; // ok
1726
}
1827

1928
function f<T extends any>(x: T) {
2029
x.children;
30+
~~~~~~~~
31+
!!! error TS2339: Property 'children' does not exist on type 'T'.
2132
x();
33+
~
34+
!!! error TS2349: This expression is not callable.
35+
!!! error TS2349: Type '{}' has no call signatures.
2236
new x();
37+
~
38+
!!! error TS2351: This expression is not constructable.
39+
!!! error TS2351: Type '{}' has no construct signatures.
2340
x[100];
2441
x['hello'];
2542
}
@@ -34,6 +51,8 @@ tests/cases/compiler/typeParameterExplicitlyExtendsAny.ts(3,7): error TS2339: Pr
3451
public static displayTree1<T extends Tree<any>>(tree: T) {
3552
// error "Property 'children' does not exist on type 'T'"
3653
tree.children;
54+
~~~~~~~~
55+
!!! error TS2339: Property 'children' does not exist on type 'T'.
3756
}
3857
}
3958

tests/baselines/reference/typeParameterExplicitlyExtendsAny.symbols

+2
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,9 @@ function fee2<T extends any>() {
2828
>t : Symbol(t, Decl(typeParameterExplicitlyExtendsAny.ts, 7, 7))
2929

3030
t.toString; // ok
31+
>t.toString : Symbol(Object.toString, Decl(lib.es5.d.ts, --, --))
3132
>t : Symbol(t, Decl(typeParameterExplicitlyExtendsAny.ts, 7, 7))
33+
>toString : Symbol(Object.toString, Decl(lib.es5.d.ts, --, --))
3234
}
3335

3436
function f<T extends any>(x: T) {

tests/baselines/reference/typeParameterExplicitlyExtendsAny.types

+5-5
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ function fee<T>() {
1717
}
1818

1919
function fee2<T extends any>() {
20-
>fee2 : <T extends any>() => void
20+
>fee2 : <T extends unknown>() => void
2121

2222
var t: T;
2323
>t : T
@@ -28,13 +28,13 @@ function fee2<T extends any>() {
2828
>blah : any
2929

3030
t.toString; // ok
31-
>t.toString : any
31+
>t.toString : () => string
3232
>t : T
33-
>toString : any
33+
>toString : () => string
3434
}
3535

3636
function f<T extends any>(x: T) {
37-
>f : <T extends any>(x: T) => void
37+
>f : <T extends unknown>(x: T) => void
3838
>x : T
3939

4040
x.children;
@@ -74,7 +74,7 @@ class MyClass {
7474
>MyClass : MyClass
7575

7676
public static displayTree1<T extends Tree<any>>(tree: T) {
77-
>displayTree1 : <T extends any>(tree: T) => void
77+
>displayTree1 : <T extends unknown>(tree: T) => void
7878
>tree : T
7979

8080
// error "Property 'children' does not exist on type 'T'"

0 commit comments

Comments
 (0)