mirror of
https://github.com/microsoft/TypeScript.git
synced 2026-07-02 06:35:09 -05:00
Merge pull request #28940 from Microsoft/explicitUnknownConstraint
Type parameter constrained to 'unknown' not assignable to '{}'
This commit is contained in:
@@ -12168,10 +12168,6 @@ namespace ts {
|
||||
return result;
|
||||
}
|
||||
|
||||
function getConstraintForRelation(type: Type) {
|
||||
return relation === definitelyAssignableRelation ? undefined : getConstraintOfType(type);
|
||||
}
|
||||
|
||||
function structuredTypeRelatedTo(source: Type, target: Type, reportErrors: boolean, isIntersectionConstituent: boolean): Ternary {
|
||||
const flags = source.flags & target.flags;
|
||||
if (relation === identityRelation && !(flags & TypeFlags.Object)) {
|
||||
@@ -12304,24 +12300,26 @@ namespace ts {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
const constraint = getConstraintForRelation(<TypeParameter>source);
|
||||
if (!constraint || (source.flags & TypeFlags.TypeParameter && constraint.flags & TypeFlags.AnyOrUnknown)) {
|
||||
// A type variable with no constraint is not related to the non-primitive object type.
|
||||
if (result = isRelatedTo(emptyObjectType, extractTypesOfKind(target, ~TypeFlags.NonPrimitive))) {
|
||||
if (relation !== definitelyAssignableRelation) {
|
||||
const constraint = getConstraintOfType(<TypeParameter>source);
|
||||
if (!constraint || (source.flags & TypeFlags.TypeParameter && constraint.flags & TypeFlags.Any)) {
|
||||
// A type variable with no constraint is not related to the non-primitive object type.
|
||||
if (result = isRelatedTo(emptyObjectType, extractTypesOfKind(target, ~TypeFlags.NonPrimitive))) {
|
||||
errorInfo = saveErrorInfo;
|
||||
return result;
|
||||
}
|
||||
}
|
||||
// hi-speed no-this-instantiation check (less accurate, but avoids costly `this`-instantiation when the constraint will suffice), see #28231 for report on why this is needed
|
||||
else if (result = isRelatedTo(constraint, target, /*reportErrors*/ false, /*headMessage*/ undefined, isIntersectionConstituent)) {
|
||||
errorInfo = saveErrorInfo;
|
||||
return result;
|
||||
}
|
||||
// slower, fuller, this-instantiated check (necessary when comparing raw `this` types from base classes), see `subclassWithPolymorphicThisIsAssignable.ts` test for example
|
||||
else if (result = isRelatedTo(getTypeWithThisArgument(constraint, source), target, reportErrors, /*headMessage*/ undefined, isIntersectionConstituent)) {
|
||||
errorInfo = saveErrorInfo;
|
||||
return result;
|
||||
}
|
||||
}
|
||||
// hi-speed no-this-instantiation check (less accurate, but avoids costly `this`-instantiation when the constraint will suffice), see #28231 for report on why this is needed
|
||||
else if (result = isRelatedTo(constraint, target, /*reportErrors*/ false, /*headMessage*/ undefined, isIntersectionConstituent)) {
|
||||
errorInfo = saveErrorInfo;
|
||||
return result;
|
||||
}
|
||||
// slower, fuller, this-instantiated check (necessary when comparing raw `this` types from base classes), see `subclassWithPolymorphicThisIsAssignable.ts` test for example
|
||||
else if (result = isRelatedTo(getTypeWithThisArgument(constraint, source), target, reportErrors, /*headMessage*/ undefined, isIntersectionConstituent)) {
|
||||
errorInfo = saveErrorInfo;
|
||||
return result;
|
||||
}
|
||||
}
|
||||
else if (source.flags & TypeFlags.Index) {
|
||||
if (result = isRelatedTo(keyofConstraintType, target, reportErrors)) {
|
||||
|
||||
@@ -17,13 +17,18 @@ tests/cases/conformance/types/unknown/unknownType1.ts(113,9): error TS2322: Type
|
||||
tests/cases/conformance/types/unknown/unknownType1.ts(114,9): error TS2322: Type 'unknown' is not assignable to type '{} | null | undefined'.
|
||||
Type 'unknown' is not assignable to type '{}'.
|
||||
tests/cases/conformance/types/unknown/unknownType1.ts(120,9): error TS2322: Type 'T' is not assignable to type 'object'.
|
||||
Type 'unknown' is not assignable to type 'object'.
|
||||
tests/cases/conformance/types/unknown/unknownType1.ts(129,5): error TS2322: Type '123' is not assignable to type '{ [x: string]: unknown; }'.
|
||||
tests/cases/conformance/types/unknown/unknownType1.ts(149,17): error TS2355: A function whose declared type is neither 'void' nor 'any' must return a value.
|
||||
tests/cases/conformance/types/unknown/unknownType1.ts(155,14): error TS2700: Rest types may only be created from object types.
|
||||
tests/cases/conformance/types/unknown/unknownType1.ts(161,5): error TS2564: Property 'a' has no initializer and is not definitely assigned in the constructor.
|
||||
tests/cases/conformance/types/unknown/unknownType1.ts(170,9): error TS2322: Type 'U' is not assignable to type '{}'.
|
||||
Type 'unknown' is not assignable to type '{}'.
|
||||
tests/cases/conformance/types/unknown/unknownType1.ts(180,5): error TS2322: Type 'T' is not assignable to type '{}'.
|
||||
Type 'unknown' is not assignable to type '{}'.
|
||||
|
||||
|
||||
==== tests/cases/conformance/types/unknown/unknownType1.ts (22 errors) ====
|
||||
==== tests/cases/conformance/types/unknown/unknownType1.ts (24 errors) ====
|
||||
// In an intersection everything absorbs unknown
|
||||
|
||||
type T00 = unknown & null; // null
|
||||
@@ -181,6 +186,7 @@ tests/cases/conformance/types/unknown/unknownType1.ts(161,5): error TS2564: Prop
|
||||
let y: object = x; // Error
|
||||
~
|
||||
!!! error TS2322: Type 'T' is not assignable to type 'object'.
|
||||
!!! error TS2322: Type 'unknown' is not assignable to type 'object'.
|
||||
}
|
||||
|
||||
// Anything but primitive assignable to { [x: string]: unknown }
|
||||
@@ -233,4 +239,27 @@ tests/cases/conformance/types/unknown/unknownType1.ts(161,5): error TS2564: Prop
|
||||
b: unknown;
|
||||
c: any;
|
||||
}
|
||||
|
||||
// Type parameter with explicit 'unknown' constraint not assignable to '{}'
|
||||
|
||||
function f30<T, U extends unknown>(t: T, u: U) {
|
||||
let x: {} = t;
|
||||
let y: {} = u;
|
||||
~
|
||||
!!! error TS2322: Type 'U' is not assignable to type '{}'.
|
||||
!!! error TS2322: Type 'unknown' is not assignable to type '{}'.
|
||||
}
|
||||
|
||||
// Repro from #26796
|
||||
|
||||
type Test1 = [unknown] extends [{}] ? true : false; // false
|
||||
type IsDefinitelyDefined<T extends unknown> = [T] extends [{}] ? true : false;
|
||||
type Test2 = IsDefinitelyDefined<unknown>; // false
|
||||
|
||||
function oops<T extends unknown>(arg: T): {} {
|
||||
return arg; // Error
|
||||
~~~~~~~~~~~
|
||||
!!! error TS2322: Type 'T' is not assignable to type '{}'.
|
||||
!!! error TS2322: Type 'unknown' is not assignable to type '{}'.
|
||||
}
|
||||
|
||||
@@ -163,6 +163,23 @@ class C1 {
|
||||
b: unknown;
|
||||
c: any;
|
||||
}
|
||||
|
||||
// Type parameter with explicit 'unknown' constraint not assignable to '{}'
|
||||
|
||||
function f30<T, U extends unknown>(t: T, u: U) {
|
||||
let x: {} = t;
|
||||
let y: {} = u;
|
||||
}
|
||||
|
||||
// Repro from #26796
|
||||
|
||||
type Test1 = [unknown] extends [{}] ? true : false; // false
|
||||
type IsDefinitelyDefined<T extends unknown> = [T] extends [{}] ? true : false;
|
||||
type Test2 = IsDefinitelyDefined<unknown>; // false
|
||||
|
||||
function oops<T extends unknown>(arg: T): {} {
|
||||
return arg; // Error
|
||||
}
|
||||
|
||||
|
||||
//// [unknownType1.js]
|
||||
@@ -276,3 +293,11 @@ var C1 = /** @class */ (function () {
|
||||
}
|
||||
return C1;
|
||||
}());
|
||||
// Type parameter with explicit 'unknown' constraint not assignable to '{}'
|
||||
function f30(t, u) {
|
||||
var x = t;
|
||||
var y = u;
|
||||
}
|
||||
function oops(arg) {
|
||||
return arg; // Error
|
||||
}
|
||||
|
||||
@@ -407,3 +407,47 @@ class C1 {
|
||||
>c : Symbol(C1.c, Decl(unknownType1.ts, 161, 15))
|
||||
}
|
||||
|
||||
// Type parameter with explicit 'unknown' constraint not assignable to '{}'
|
||||
|
||||
function f30<T, U extends unknown>(t: T, u: U) {
|
||||
>f30 : Symbol(f30, Decl(unknownType1.ts, 163, 1))
|
||||
>T : Symbol(T, Decl(unknownType1.ts, 167, 13))
|
||||
>U : Symbol(U, Decl(unknownType1.ts, 167, 15))
|
||||
>t : Symbol(t, Decl(unknownType1.ts, 167, 35))
|
||||
>T : Symbol(T, Decl(unknownType1.ts, 167, 13))
|
||||
>u : Symbol(u, Decl(unknownType1.ts, 167, 40))
|
||||
>U : Symbol(U, Decl(unknownType1.ts, 167, 15))
|
||||
|
||||
let x: {} = t;
|
||||
>x : Symbol(x, Decl(unknownType1.ts, 168, 7))
|
||||
>t : Symbol(t, Decl(unknownType1.ts, 167, 35))
|
||||
|
||||
let y: {} = u;
|
||||
>y : Symbol(y, Decl(unknownType1.ts, 169, 7))
|
||||
>u : Symbol(u, Decl(unknownType1.ts, 167, 40))
|
||||
}
|
||||
|
||||
// Repro from #26796
|
||||
|
||||
type Test1 = [unknown] extends [{}] ? true : false; // false
|
||||
>Test1 : Symbol(Test1, Decl(unknownType1.ts, 170, 1))
|
||||
|
||||
type IsDefinitelyDefined<T extends unknown> = [T] extends [{}] ? true : false;
|
||||
>IsDefinitelyDefined : Symbol(IsDefinitelyDefined, Decl(unknownType1.ts, 174, 51))
|
||||
>T : Symbol(T, Decl(unknownType1.ts, 175, 25))
|
||||
>T : Symbol(T, Decl(unknownType1.ts, 175, 25))
|
||||
|
||||
type Test2 = IsDefinitelyDefined<unknown>; // false
|
||||
>Test2 : Symbol(Test2, Decl(unknownType1.ts, 175, 78))
|
||||
>IsDefinitelyDefined : Symbol(IsDefinitelyDefined, Decl(unknownType1.ts, 174, 51))
|
||||
|
||||
function oops<T extends unknown>(arg: T): {} {
|
||||
>oops : Symbol(oops, Decl(unknownType1.ts, 176, 42))
|
||||
>T : Symbol(T, Decl(unknownType1.ts, 178, 14))
|
||||
>arg : Symbol(arg, Decl(unknownType1.ts, 178, 33))
|
||||
>T : Symbol(T, Decl(unknownType1.ts, 178, 14))
|
||||
|
||||
return arg; // Error
|
||||
>arg : Symbol(arg, Decl(unknownType1.ts, 178, 33))
|
||||
}
|
||||
|
||||
|
||||
@@ -453,3 +453,42 @@ class C1 {
|
||||
>c : any
|
||||
}
|
||||
|
||||
// Type parameter with explicit 'unknown' constraint not assignable to '{}'
|
||||
|
||||
function f30<T, U extends unknown>(t: T, u: U) {
|
||||
>f30 : <T, U extends unknown>(t: T, u: U) => void
|
||||
>t : T
|
||||
>u : U
|
||||
|
||||
let x: {} = t;
|
||||
>x : {}
|
||||
>t : T
|
||||
|
||||
let y: {} = u;
|
||||
>y : {}
|
||||
>u : U
|
||||
}
|
||||
|
||||
// Repro from #26796
|
||||
|
||||
type Test1 = [unknown] extends [{}] ? true : false; // false
|
||||
>Test1 : false
|
||||
>true : true
|
||||
>false : false
|
||||
|
||||
type IsDefinitelyDefined<T extends unknown> = [T] extends [{}] ? true : false;
|
||||
>IsDefinitelyDefined : IsDefinitelyDefined<T>
|
||||
>true : true
|
||||
>false : false
|
||||
|
||||
type Test2 = IsDefinitelyDefined<unknown>; // false
|
||||
>Test2 : false
|
||||
|
||||
function oops<T extends unknown>(arg: T): {} {
|
||||
>oops : <T extends unknown>(arg: T) => {}
|
||||
>arg : T
|
||||
|
||||
return arg; // Error
|
||||
>arg : T
|
||||
}
|
||||
|
||||
|
||||
@@ -164,3 +164,20 @@ class C1 {
|
||||
b: unknown;
|
||||
c: any;
|
||||
}
|
||||
|
||||
// Type parameter with explicit 'unknown' constraint not assignable to '{}'
|
||||
|
||||
function f30<T, U extends unknown>(t: T, u: U) {
|
||||
let x: {} = t;
|
||||
let y: {} = u;
|
||||
}
|
||||
|
||||
// Repro from #26796
|
||||
|
||||
type Test1 = [unknown] extends [{}] ? true : false; // false
|
||||
type IsDefinitelyDefined<T extends unknown> = [T] extends [{}] ? true : false;
|
||||
type Test2 = IsDefinitelyDefined<unknown>; // false
|
||||
|
||||
function oops<T extends unknown>(arg: T): {} {
|
||||
return arg; // Error
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user