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

Reinterpret a type parameter constrained to any as an upper bound constraint #29571

Merged
merged 5 commits into from
Mar 3, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 12 additions & 2 deletions src/compiler/checker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10945,8 +10945,18 @@ namespace ts {
}
else {
const constraintDeclaration = getConstraintDeclaration(typeParameter);
typeParameter.constraint = constraintDeclaration ? getTypeFromTypeNode(constraintDeclaration) :
getInferredTypeParameterConstraint(typeParameter) || noConstraintType;
if (!constraintDeclaration) {
typeParameter.constraint = getInferredTypeParameterConstraint(typeParameter) || noConstraintType;
}
else {
let type = getTypeFromTypeNode(constraintDeclaration);
if (type.flags & TypeFlags.Any && type !== errorType) { // Allow errorType to propegate to keep downstream errors suppressed
// use keyofConstraintType as the base constraint for mapped type key constraints (unknown isn;t assignable to that, but `any` was),
// use unknown otherwise
type = constraintDeclaration.parent.parent.kind === SyntaxKind.MappedType ? keyofConstraintType : unknownType;
}
typeParameter.constraint = type;
}
}
}
return typeParameter.constraint === noConstraintType ? undefined : typeParameter.constraint;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -162,7 +162,7 @@ declare function g1<T>(x: T): T;
>x : T

declare function g2<T extends any>(x: T): T;
>g2 : <T extends any>(x: T) => T
>g2 : <T extends unknown>(x: T) => T
>x : T

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

g2((x = 1) => 0); // number
>g2((x = 1) => 0) : (x?: number) => 0
>g2 : <T extends any>(x: T) => T
>g2 : <T extends unknown>(x: T) => T
>(x = 1) => 0 : (x?: number) => 0
>x : number
>1 : 1
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
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>'.
Type 'ComposedComponentProps & { myProp: number; }' is not assignable to type 'Readonly<WrapperComponentProps>'.


==== tests/cases/compiler/jsxExcessPropsAndAssignability.tsx (1 errors) ====
/// <reference path="/.lib/react16.d.ts" />

import * as React from 'react';

const myHoc = <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} />;
~~~~~~~~~~~~~~~~
!!! error TS2322: Type 'ComposedComponentProps & { myProp: number; }' is not assignable to type 'IntrinsicAttributes & IntrinsicClassAttributes<Component<WrapperComponentProps, any, any>> & Readonly<{ children?: ReactNode; }> & Readonly<WrapperComponentProps>'.
!!! error TS2322: Type 'ComposedComponentProps & { myProp: number; }' is not assignable to type 'Readonly<WrapperComponentProps>'.
};

44 changes: 44 additions & 0 deletions tests/baselines/reference/jsxExcessPropsAndAssignability.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
//// [jsxExcessPropsAndAssignability.tsx]
/// <reference path="/.lib/react16.d.ts" />

import * as React from 'react';

const myHoc = <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} />;
};


//// [jsxExcessPropsAndAssignability.js]
"use strict";
/// <reference path="react16.d.ts" />
var __assign = (this && this.__assign) || function () {
__assign = Object.assign || function(t) {
for (var s, i = 1, n = arguments.length; i < n; i++) {
s = arguments[i];
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
t[p] = s[p];
}
return t;
};
return __assign.apply(this, arguments);
};
exports.__esModule = true;
var React = require("react");
var myHoc = function (ComposedComponent) {
var WrapperComponent = null;
var props = null;
// Expected no error, got none - good
React.createElement(WrapperComponent, __assign({}, props, { myProp: '1000000' }));
// Expected error, but got none - bad!
React.createElement(WrapperComponent, __assign({}, props, { myProp: 1000000 }));
};
46 changes: 46 additions & 0 deletions tests/baselines/reference/jsxExcessPropsAndAssignability.symbols
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
=== tests/cases/compiler/jsxExcessPropsAndAssignability.tsx ===
/// <reference path="react16.d.ts" />

import * as React from 'react';
>React : Symbol(React, Decl(jsxExcessPropsAndAssignability.tsx, 2, 6))

const myHoc = <ComposedComponentProps extends any>(
>myHoc : Symbol(myHoc, Decl(jsxExcessPropsAndAssignability.tsx, 4, 5))
>ComposedComponentProps : Symbol(ComposedComponentProps, Decl(jsxExcessPropsAndAssignability.tsx, 4, 15))

ComposedComponent: React.ComponentClass<ComposedComponentProps>,
>ComposedComponent : Symbol(ComposedComponent, Decl(jsxExcessPropsAndAssignability.tsx, 4, 51))
>React : Symbol(React, Decl(jsxExcessPropsAndAssignability.tsx, 2, 6))
>ComponentClass : Symbol(React.ComponentClass, Decl(react16.d.ts, 421, 9))
>ComposedComponentProps : Symbol(ComposedComponentProps, Decl(jsxExcessPropsAndAssignability.tsx, 4, 15))

) => {
type WrapperComponentProps = ComposedComponentProps & { myProp: string };
>WrapperComponentProps : Symbol(WrapperComponentProps, Decl(jsxExcessPropsAndAssignability.tsx, 6, 6))
>ComposedComponentProps : Symbol(ComposedComponentProps, Decl(jsxExcessPropsAndAssignability.tsx, 4, 15))
>myProp : Symbol(myProp, Decl(jsxExcessPropsAndAssignability.tsx, 7, 59))

const WrapperComponent: React.ComponentClass<WrapperComponentProps> = null as any;
>WrapperComponent : Symbol(WrapperComponent, Decl(jsxExcessPropsAndAssignability.tsx, 8, 9))
>React : Symbol(React, Decl(jsxExcessPropsAndAssignability.tsx, 2, 6))
>ComponentClass : Symbol(React.ComponentClass, Decl(react16.d.ts, 421, 9))
>WrapperComponentProps : Symbol(WrapperComponentProps, Decl(jsxExcessPropsAndAssignability.tsx, 6, 6))

const props: ComposedComponentProps = null as any;
>props : Symbol(props, Decl(jsxExcessPropsAndAssignability.tsx, 10, 9))
>ComposedComponentProps : Symbol(ComposedComponentProps, Decl(jsxExcessPropsAndAssignability.tsx, 4, 15))

// Expected no error, got none - good
<WrapperComponent {...props} myProp={'1000000'} />;
>WrapperComponent : Symbol(WrapperComponent, Decl(jsxExcessPropsAndAssignability.tsx, 8, 9))
>props : Symbol(props, Decl(jsxExcessPropsAndAssignability.tsx, 10, 9))
>myProp : Symbol(myProp, Decl(jsxExcessPropsAndAssignability.tsx, 13, 32))

// Expected error, but got none - bad!
<WrapperComponent {...props} myProp={1000000} />;
>WrapperComponent : Symbol(WrapperComponent, Decl(jsxExcessPropsAndAssignability.tsx, 8, 9))
>props : Symbol(props, Decl(jsxExcessPropsAndAssignability.tsx, 10, 9))
>myProp : Symbol(myProp, Decl(jsxExcessPropsAndAssignability.tsx, 15, 32))

};

48 changes: 48 additions & 0 deletions tests/baselines/reference/jsxExcessPropsAndAssignability.types
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
=== tests/cases/compiler/jsxExcessPropsAndAssignability.tsx ===
/// <reference path="react16.d.ts" />

import * as React from 'react';
>React : typeof React

const myHoc = <ComposedComponentProps extends any>(
>myHoc : <ComposedComponentProps extends unknown>(ComposedComponent: React.ComponentClass<ComposedComponentProps, any>) => void
><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

ComposedComponent: React.ComponentClass<ComposedComponentProps>,
>ComposedComponent : React.ComponentClass<ComposedComponentProps, any>
>React : any

) => {
type WrapperComponentProps = ComposedComponentProps & { myProp: string };
>WrapperComponentProps : ComposedComponentProps & { myProp: string; }
>myProp : string

const WrapperComponent: React.ComponentClass<WrapperComponentProps> = null as any;
>WrapperComponent : React.ComponentClass<ComposedComponentProps & { myProp: string; }, any>
>React : any
>null as any : any
>null : null

const props: ComposedComponentProps = null as any;
>props : ComposedComponentProps
>null as any : any
>null : null

// Expected no error, got none - good
<WrapperComponent {...props} myProp={'1000000'} />;
><WrapperComponent {...props} myProp={'1000000'} /> : JSX.Element
>WrapperComponent : React.ComponentClass<ComposedComponentProps & { myProp: string; }, any>
>props : ComposedComponentProps
>myProp : "1000000"
>'1000000' : "1000000"

// Expected error, but got none - bad!
<WrapperComponent {...props} myProp={1000000} />;
><WrapperComponent {...props} myProp={1000000} /> : JSX.Element
>WrapperComponent : React.ComponentClass<ComposedComponentProps & { myProp: string; }, any>
>props : ComposedComponentProps
>myProp : number
>1000000 : 1000000

};

2 changes: 1 addition & 1 deletion tests/baselines/reference/mappedTypeWithAny.types
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ declare let x0: keyof any;
>x0 : string | number | symbol

declare let x1: { [P in any]: Item };
>x1 : { [x: string]: Item; }
>x1 : { [x: string]: Item; [x: number]: Item; }

declare let x2: { [P in string]: Item };
>x2 : { [x: string]: Item; }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -357,7 +357,7 @@ x<string, string, string>(null, null, null); // Error

// Generic call with multiple parameters of generic type passed arguments with no best common type
function someGenerics9<T extends any>(a: T, b: T, c: T): T {
>someGenerics9 : <T extends any>(a: T, b: T, c: T) => T
>someGenerics9 : <T extends unknown>(a: T, b: T, c: T) => T
>a : T
>b : T
>c : T
Expand All @@ -368,7 +368,7 @@ function someGenerics9<T extends any>(a: T, b: T, c: T): T {
var a9a = someGenerics9('', 0, []);
>a9a : string
>someGenerics9('', 0, []) : ""
>someGenerics9 : <T extends any>(a: T, b: T, c: T) => T
>someGenerics9 : <T extends unknown>(a: T, b: T, c: T) => T
>'' : ""
>0 : 0
>[] : undefined[]
Expand All @@ -379,7 +379,7 @@ var a9a: {};
var a9b = someGenerics9<{ a?: number; b?: string; }>({ a: 0 }, { b: '' }, null);
>a9b : { a?: number; b?: string; }
>someGenerics9<{ a?: number; b?: string; }>({ a: 0 }, { b: '' }, null) : { a?: number; b?: string; }
>someGenerics9 : <T extends any>(a: T, b: T, c: T) => T
>someGenerics9 : <T extends unknown>(a: T, b: T, c: T) => T
>a : number
>b : string
>{ a: 0 } : { a: number; }
Expand Down Expand Up @@ -413,7 +413,7 @@ interface A92 {
var a9e = someGenerics9(undefined, { x: 6, z: window }, { x: 6, y: '' });
>a9e : { x: number; z: Window & typeof globalThis; y?: undefined; } | { x: number; y: string; z?: undefined; }
>someGenerics9(undefined, { x: 6, z: window }, { x: 6, y: '' }) : { x: number; z: Window & typeof globalThis; y?: undefined; } | { x: number; y: string; z?: undefined; }
>someGenerics9 : <T extends any>(a: T, b: T, c: T) => T
>someGenerics9 : <T extends unknown>(a: T, b: T, c: T) => T
>undefined : undefined
>{ x: 6, z: window } : { x: number; z: Window & typeof globalThis; }
>x : number
Expand All @@ -432,7 +432,7 @@ var a9e: {};
var a9f = someGenerics9<A92>(undefined, { x: 6, z: window }, { x: 6, y: '' });
>a9f : A92
>someGenerics9<A92>(undefined, { x: 6, z: window }, { x: 6, y: '' }) : A92
>someGenerics9 : <T extends any>(a: T, b: T, c: T) => T
>someGenerics9 : <T extends unknown>(a: T, b: T, c: T) => T
>undefined : undefined
>{ x: 6, z: window } : { x: number; z: Window & typeof globalThis; }
>x : number
Expand All @@ -452,7 +452,7 @@ var a9f: A92;
var a9d = someGenerics9({ x: 3 }, { x: 6 }, { x: 6 });
>a9d : { x: number; }
>someGenerics9({ x: 3 }, { x: 6 }, { x: 6 }) : { x: number; }
>someGenerics9 : <T extends any>(a: T, b: T, c: T) => T
>someGenerics9 : <T extends unknown>(a: T, b: T, c: T) => T
>{ x: 3 } : { x: number; }
>x : number
>3 : 3
Expand All @@ -474,7 +474,7 @@ var anyVar: any;
var a = someGenerics9(7, anyVar, 4);
>a : any
>someGenerics9(7, anyVar, 4) : any
>someGenerics9 : <T extends any>(a: T, b: T, c: T) => T
>someGenerics9 : <T extends unknown>(a: T, b: T, c: T) => T
>7 : 7
>anyVar : any
>4 : 4
Expand All @@ -486,7 +486,7 @@ var a: any;
var arr = someGenerics9([], null, undefined);
>arr : any[]
>someGenerics9([], null, undefined) : any[]
>someGenerics9 : <T extends any>(a: T, b: T, c: T) => T
>someGenerics9 : <T extends unknown>(a: T, b: T, c: T) => T
>[] : undefined[]
>null : null
>undefined : undefined
Expand Down
2 changes: 1 addition & 1 deletion tests/baselines/reference/typeParameterConstraints1.types
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
=== tests/cases/compiler/typeParameterConstraints1.ts ===
function foo1<T extends any>(test: T) { }
>foo1 : <T extends any>(test: T) => void
>foo1 : <T extends unknown>(test: T) => void
>test : T

function foo2<T extends number>(test: T) { }
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,14 @@
tests/cases/compiler/typeParameterExplicitlyExtendsAny.ts(3,7): error TS2339: Property 'blah' does not exist on type 'T'.
tests/cases/compiler/typeParameterExplicitlyExtendsAny.ts(9,7): error TS2339: Property 'blah' does not exist on type 'T'.
tests/cases/compiler/typeParameterExplicitlyExtendsAny.ts(14,7): error TS2339: Property 'children' does not exist on type 'T'.
tests/cases/compiler/typeParameterExplicitlyExtendsAny.ts(15,5): error TS2349: This expression is not callable.
Type '{}' has no call signatures.
tests/cases/compiler/typeParameterExplicitlyExtendsAny.ts(16,9): error TS2351: This expression is not constructable.
Type '{}' has no construct signatures.
tests/cases/compiler/typeParameterExplicitlyExtendsAny.ts(30,14): error TS2339: Property 'children' does not exist on type 'T'.


==== tests/cases/compiler/typeParameterExplicitlyExtendsAny.ts (1 errors) ====
==== tests/cases/compiler/typeParameterExplicitlyExtendsAny.ts (6 errors) ====
function fee<T>() {
var t: T;
t.blah; // Error
Expand All @@ -13,13 +20,23 @@ tests/cases/compiler/typeParameterExplicitlyExtendsAny.ts(3,7): error TS2339: Pr
function fee2<T extends any>() {
var t: T;
t.blah; // ok
~~~~
!!! error TS2339: Property 'blah' does not exist on type 'T'.
t.toString; // ok
}

function f<T extends any>(x: T) {
x.children;
~~~~~~~~
!!! error TS2339: Property 'children' does not exist on type 'T'.
x();
~
!!! error TS2349: This expression is not callable.
!!! error TS2349: Type '{}' has no call signatures.
new x();
~
!!! error TS2351: This expression is not constructable.
!!! error TS2351: Type '{}' has no construct signatures.
x[100];
x['hello'];
}
Expand All @@ -34,6 +51,8 @@ tests/cases/compiler/typeParameterExplicitlyExtendsAny.ts(3,7): error TS2339: Pr
public static displayTree1<T extends Tree<any>>(tree: T) {
// error "Property 'children' does not exist on type 'T'"
tree.children;
~~~~~~~~
!!! error TS2339: Property 'children' does not exist on type 'T'.
}
}

Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,9 @@ function fee2<T extends any>() {
>t : Symbol(t, Decl(typeParameterExplicitlyExtendsAny.ts, 7, 7))

t.toString; // ok
>t.toString : Symbol(Object.toString, Decl(lib.es5.d.ts, --, --))
>t : Symbol(t, Decl(typeParameterExplicitlyExtendsAny.ts, 7, 7))
>toString : Symbol(Object.toString, Decl(lib.es5.d.ts, --, --))
}

function f<T extends any>(x: T) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ function fee<T>() {
}

function fee2<T extends any>() {
>fee2 : <T extends any>() => void
>fee2 : <T extends unknown>() => void

var t: T;
>t : T
Expand All @@ -28,13 +28,13 @@ function fee2<T extends any>() {
>blah : any

t.toString; // ok
>t.toString : any
>t.toString : () => string
>t : T
>toString : any
>toString : () => string
}

function f<T extends any>(x: T) {
>f : <T extends any>(x: T) => void
>f : <T extends unknown>(x: T) => void
>x : T

x.children;
Expand Down Expand Up @@ -74,7 +74,7 @@ class MyClass {
>MyClass : MyClass

public static displayTree1<T extends Tree<any>>(tree: T) {
>displayTree1 : <T extends any>(tree: T) => void
>displayTree1 : <T extends unknown>(tree: T) => void
>tree : T

// error "Property 'children' does not exist on type 'T'"
Expand Down
Loading