Use identity with the permissive instantation to detect nongenric instances and disable variance probing on nongeneric instances (#29981)

* Use identity with the restrictive instantation to detect nongenric instances and disable variance probing on nongeneric instances

* Generalize to also include interfaces, add test case, still perform argument comparisons for postive comparisons if possible

* Actually accept baselines, lol

* Reduce deep nesting limit just a bit so yargs still builds

* Handle circular identities in isNonGeneric

* Use a simple traversal of the types rather than the restrictive instantiation

* Cache the bits using an existing field to further reduce any time nongeneric check takes

* Revert to using an existing mapper, use permissive > restrictive

* Revert constant change

* And revert the comment, too
This commit is contained in:
Wesley Wigham
2019-02-27 14:12:30 -08:00
committed by GitHub
parent 0d93eb9218
commit 13c08ab32b
18 changed files with 430 additions and 294 deletions

View File

@@ -12822,12 +12822,22 @@ namespace ts {
}
return Ternary.False;
function isNonGeneric(type: Type) {
// If we're already in identity relationship checking, we should use `isRelatedTo`
// to catch the `Maybe` from an excessively deep type (which we then assume means
// that the type could possibly contain a generic)
if (relation === identityRelation) {
return isRelatedTo(type, getPermissiveInstantiation(type)) === Ternary.True;
}
return isTypeIdenticalTo(type, getPermissiveInstantiation(type));
}
function relateVariances(sourceTypeArguments: ReadonlyArray<Type> | undefined, targetTypeArguments: ReadonlyArray<Type> | undefined, variances: Variance[]) {
if (result = typeArgumentsRelatedTo(sourceTypeArguments, targetTypeArguments, variances, reportErrors)) {
return result;
}
const isCovariantVoid = targetTypeArguments && hasCovariantVoidArgument(targetTypeArguments, variances);
varianceCheckFailed = !isCovariantVoid;
const allowStructuralFallback = (targetTypeArguments && hasCovariantVoidArgument(targetTypeArguments, variances)) || isNonGeneric(source) || isNonGeneric(target);
varianceCheckFailed = !allowStructuralFallback;
// The type arguments did not relate appropriately, but it may be because we have no variance
// information (in which case typeArgumentsRelatedTo defaulted to covariance for all type
// arguments). It might also be the case that the target type has a 'void' type argument for
@@ -12835,7 +12845,7 @@ namespace ts {
// (in which case any type argument is permitted on the source side). In those cases we proceed
// with a structural comparison. Otherwise, we know for certain the instantiations aren't
// related and we can return here.
if (variances !== emptyArray && !isCovariantVoid) {
if (variances !== emptyArray && !allowStructuralFallback) {
// In some cases generic types that are covariant in regular type checking mode become
// invariant in --strictFunctionTypes mode because one or more type parameters are used in
// both co- and contravariant positions. In order to make it easier to diagnose *why* such

View File

@@ -1,32 +0,0 @@
tests/cases/compiler/checkInfiniteExpansionTermination.ts(16,1): error TS2322: Type 'ISubject<Bar>' is not assignable to type 'IObservable<Foo>'.
Types of property 'n' are incompatible.
Type 'IObservable<Bar[]>' is not assignable to type 'IObservable<Foo[]>'.
Type 'Bar[]' is not assignable to type 'Foo[]'.
Property 'x' is missing in type 'Bar' but required in type 'Foo'.
==== tests/cases/compiler/checkInfiniteExpansionTermination.ts (1 errors) ====
// Regression test for #1002
// Before fix this code would cause infinite loop
interface IObservable<T> {
n: IObservable<T[]>; // Needed, must be T[]
}
// Needed
interface ISubject<T> extends IObservable<T> { }
interface Foo { x }
interface Bar { y }
var values: IObservable<Foo>;
var values2: ISubject<Bar>;
values = values2;
~~~~~~
!!! error TS2322: Type 'ISubject<Bar>' is not assignable to type 'IObservable<Foo>'.
!!! error TS2322: Types of property 'n' are incompatible.
!!! error TS2322: Type 'IObservable<Bar[]>' is not assignable to type 'IObservable<Foo[]>'.
!!! error TS2322: Type 'Bar[]' is not assignable to type 'Foo[]'.
!!! error TS2322: Property 'x' is missing in type 'Bar' but required in type 'Foo'.
!!! related TS2728 tests/cases/compiler/checkInfiniteExpansionTermination.ts:11:17: 'x' is declared here.

View File

@@ -1,52 +0,0 @@
tests/cases/compiler/invariantGenericErrorElaboration.ts(3,7): error TS2322: Type 'Num' is not assignable to type 'Runtype<any>'.
Types of property 'constraint' are incompatible.
Type 'Constraint<Num>' is not assignable to type 'Constraint<Runtype<any>>'.
Types of property 'constraint' are incompatible.
Type 'Constraint<Constraint<Num>>' is not assignable to type 'Constraint<Constraint<Runtype<any>>>'.
Types of property 'constraint' are incompatible.
Type 'Constraint<Constraint<Constraint<Num>>>' is not assignable to type 'Constraint<Constraint<Constraint<Runtype<any>>>>'.
Type 'Constraint<Constraint<Runtype<any>>>' is not assignable to type 'Constraint<Constraint<Num>>'.
Types of property 'underlying' are incompatible.
Type 'Constraint<Runtype<any>>' is not assignable to type 'Constraint<Num>'.
tests/cases/compiler/invariantGenericErrorElaboration.ts(4,19): error TS2322: Type 'Num' is not assignable to type 'Runtype<any>'.
==== tests/cases/compiler/invariantGenericErrorElaboration.ts (2 errors) ====
// Repro from #19746
const wat: Runtype<any> = Num;
~~~
!!! error TS2322: Type 'Num' is not assignable to type 'Runtype<any>'.
!!! error TS2322: Types of property 'constraint' are incompatible.
!!! error TS2322: Type 'Constraint<Num>' is not assignable to type 'Constraint<Runtype<any>>'.
!!! error TS2322: Types of property 'constraint' are incompatible.
!!! error TS2322: Type 'Constraint<Constraint<Num>>' is not assignable to type 'Constraint<Constraint<Runtype<any>>>'.
!!! error TS2322: Types of property 'constraint' are incompatible.
!!! error TS2322: Type 'Constraint<Constraint<Constraint<Num>>>' is not assignable to type 'Constraint<Constraint<Constraint<Runtype<any>>>>'.
!!! error TS2322: Type 'Constraint<Constraint<Runtype<any>>>' is not assignable to type 'Constraint<Constraint<Num>>'.
!!! error TS2322: Types of property 'underlying' are incompatible.
!!! error TS2322: Type 'Constraint<Runtype<any>>' is not assignable to type 'Constraint<Num>'.
!!! related TS2728 tests/cases/compiler/invariantGenericErrorElaboration.ts:12:3: 'tag' is declared here.
const Foo = Obj({ foo: Num })
~~~
!!! error TS2322: Type 'Num' is not assignable to type 'Runtype<any>'.
!!! related TS6501 tests/cases/compiler/invariantGenericErrorElaboration.ts:17:34: The expected type comes from this index signature.
interface Runtype<A> {
constraint: Constraint<this>
witness: A
}
interface Num extends Runtype<number> {
tag: 'number'
}
declare const Num: Num
interface Obj<O extends { [_ in string]: Runtype<any> }> extends Runtype<{[K in keyof O]: O[K]['witness'] }> {}
declare function Obj<O extends { [_: string]: Runtype<any> }>(fields: O): Obj<O>;
interface Constraint<A extends Runtype<any>> extends Runtype<A['witness']> {
underlying: A,
check: (x: A['witness']) => void,
}

View File

@@ -6,8 +6,8 @@ const wat: Runtype<any> = Num;
>Num : Num
const Foo = Obj({ foo: Num })
>Foo : any
>Obj({ foo: Num }) : any
>Foo : Obj<{ foo: Num; }>
>Obj({ foo: Num }) : Obj<{ foo: Num; }>
>Obj : <O extends { [_: string]: Runtype<any>; }>(fields: O) => Obj<O>
>{ foo: Num } : { foo: Num; }
>foo : Num

View File

@@ -34,9 +34,7 @@ tests/cases/conformance/types/mapped/mappedTypeRelationships.ts(66,5): error TS2
tests/cases/conformance/types/mapped/mappedTypeRelationships.ts(66,5): error TS2542: Index signature in type 'Readonly<U>' only permits reading.
tests/cases/conformance/types/mapped/mappedTypeRelationships.ts(72,5): error TS2322: Type 'Partial<T>' is not assignable to type 'T'.
tests/cases/conformance/types/mapped/mappedTypeRelationships.ts(78,5): error TS2322: Type 'Partial<Thing>' is not assignable to type 'Partial<T>'.
Type 'Thing' is not assignable to type 'T'.
tests/cases/conformance/types/mapped/mappedTypeRelationships.ts(88,5): error TS2322: Type 'Readonly<Thing>' is not assignable to type 'Readonly<T>'.
Type 'Thing' is not assignable to type 'T'.
tests/cases/conformance/types/mapped/mappedTypeRelationships.ts(127,5): error TS2322: Type 'Partial<U>' is not assignable to type 'Identity<U>'.
tests/cases/conformance/types/mapped/mappedTypeRelationships.ts(143,5): error TS2322: Type '{ [P in keyof T]: T[P]; }' is not assignable to type '{ [P in keyof T]: U[P]; }'.
Type 'T[P]' is not assignable to type 'U[P]'.
@@ -199,7 +197,6 @@ tests/cases/conformance/types/mapped/mappedTypeRelationships.ts(168,5): error TS
y = x; // Error
~
!!! error TS2322: Type 'Partial<Thing>' is not assignable to type 'Partial<T>'.
!!! error TS2322: Type 'Thing' is not assignable to type 'T'.
}
function f40<T>(x: T, y: Readonly<T>) {
@@ -212,7 +209,6 @@ tests/cases/conformance/types/mapped/mappedTypeRelationships.ts(168,5): error TS
y = x; // Error
~
!!! error TS2322: Type 'Readonly<Thing>' is not assignable to type 'Readonly<T>'.
!!! error TS2322: Type 'Thing' is not assignable to type 'T'.
}
type Item = {

View File

@@ -0,0 +1,18 @@
//// [nongenericPartialInstantiationsRelatedInBothDirections.ts]
interface Foo {
a: number;
b: number;
bar: string;
}
interface ObjectContaining<T> {
new (sample: Partial<T>): Partial<T>
}
declare let cafoo: ObjectContaining<{ a: number, foo: number }>;
declare let cfoo: ObjectContaining<Foo>;
cfoo = cafoo;
cafoo = cfoo;
//// [nongenericPartialInstantiationsRelatedInBothDirections.js]
cfoo = cafoo;
cafoo = cfoo;

View File

@@ -0,0 +1,43 @@
=== tests/cases/compiler/nongenericPartialInstantiationsRelatedInBothDirections.ts ===
interface Foo {
>Foo : Symbol(Foo, Decl(nongenericPartialInstantiationsRelatedInBothDirections.ts, 0, 0))
a: number;
>a : Symbol(Foo.a, Decl(nongenericPartialInstantiationsRelatedInBothDirections.ts, 0, 15))
b: number;
>b : Symbol(Foo.b, Decl(nongenericPartialInstantiationsRelatedInBothDirections.ts, 1, 14))
bar: string;
>bar : Symbol(Foo.bar, Decl(nongenericPartialInstantiationsRelatedInBothDirections.ts, 2, 14))
}
interface ObjectContaining<T> {
>ObjectContaining : Symbol(ObjectContaining, Decl(nongenericPartialInstantiationsRelatedInBothDirections.ts, 4, 1))
>T : Symbol(T, Decl(nongenericPartialInstantiationsRelatedInBothDirections.ts, 5, 27))
new (sample: Partial<T>): Partial<T>
>sample : Symbol(sample, Decl(nongenericPartialInstantiationsRelatedInBothDirections.ts, 6, 7))
>Partial : Symbol(Partial, Decl(lib.es5.d.ts, --, --))
>T : Symbol(T, Decl(nongenericPartialInstantiationsRelatedInBothDirections.ts, 5, 27))
>Partial : Symbol(Partial, Decl(lib.es5.d.ts, --, --))
>T : Symbol(T, Decl(nongenericPartialInstantiationsRelatedInBothDirections.ts, 5, 27))
}
declare let cafoo: ObjectContaining<{ a: number, foo: number }>;
>cafoo : Symbol(cafoo, Decl(nongenericPartialInstantiationsRelatedInBothDirections.ts, 8, 11))
>ObjectContaining : Symbol(ObjectContaining, Decl(nongenericPartialInstantiationsRelatedInBothDirections.ts, 4, 1))
>a : Symbol(a, Decl(nongenericPartialInstantiationsRelatedInBothDirections.ts, 8, 37))
>foo : Symbol(foo, Decl(nongenericPartialInstantiationsRelatedInBothDirections.ts, 8, 48))
declare let cfoo: ObjectContaining<Foo>;
>cfoo : Symbol(cfoo, Decl(nongenericPartialInstantiationsRelatedInBothDirections.ts, 9, 11))
>ObjectContaining : Symbol(ObjectContaining, Decl(nongenericPartialInstantiationsRelatedInBothDirections.ts, 4, 1))
>Foo : Symbol(Foo, Decl(nongenericPartialInstantiationsRelatedInBothDirections.ts, 0, 0))
cfoo = cafoo;
>cfoo : Symbol(cfoo, Decl(nongenericPartialInstantiationsRelatedInBothDirections.ts, 9, 11))
>cafoo : Symbol(cafoo, Decl(nongenericPartialInstantiationsRelatedInBothDirections.ts, 8, 11))
cafoo = cfoo;
>cafoo : Symbol(cafoo, Decl(nongenericPartialInstantiationsRelatedInBothDirections.ts, 8, 11))
>cfoo : Symbol(cfoo, Decl(nongenericPartialInstantiationsRelatedInBothDirections.ts, 9, 11))

View File

@@ -0,0 +1,33 @@
=== tests/cases/compiler/nongenericPartialInstantiationsRelatedInBothDirections.ts ===
interface Foo {
a: number;
>a : number
b: number;
>b : number
bar: string;
>bar : string
}
interface ObjectContaining<T> {
new (sample: Partial<T>): Partial<T>
>sample : Partial<T>
}
declare let cafoo: ObjectContaining<{ a: number, foo: number }>;
>cafoo : ObjectContaining<{ a: number; foo: number; }>
>a : number
>foo : number
declare let cfoo: ObjectContaining<Foo>;
>cfoo : ObjectContaining<Foo>
cfoo = cafoo;
>cfoo = cafoo : ObjectContaining<{ a: number; foo: number; }>
>cfoo : ObjectContaining<Foo>
>cafoo : ObjectContaining<{ a: number; foo: number; }>
cafoo = cfoo;
>cafoo = cfoo : ObjectContaining<Foo>
>cafoo : ObjectContaining<{ a: number; foo: number; }>
>cfoo : ObjectContaining<Foo>

View File

@@ -1,27 +0,0 @@
tests/cases/compiler/recursiveTypeComparison.ts(14,5): error TS2322: Type 'Observable<{}>' is not assignable to type 'Property<number>'.
Types of property 'needThisOne' are incompatible.
Type 'Observable<{}>' is not assignable to type 'Observable<number>'.
Type '{}' is not assignable to type 'number'.
==== tests/cases/compiler/recursiveTypeComparison.ts (1 errors) ====
// Before fix this would take an exceeding long time to complete (#1170)
interface Observable<T> {
// This member can't be of type T, Property<T>, or Observable<anything but T>
needThisOne: Observable<T>;
// Add more to make it slower
expo1: Property<T[]>; // 0.31 seconds in check
expo2: Property<T[]>; // 3.11 seconds
expo3: Property<T[]>; // 82.28 seconds
}
interface Property<T> extends Observable<T> { }
var p: Observable<{}>;
var stuck: Property<number> = p;
~~~~~
!!! error TS2322: Type 'Observable<{}>' is not assignable to type 'Property<number>'.
!!! error TS2322: Types of property 'needThisOne' are incompatible.
!!! error TS2322: Type 'Observable<{}>' is not assignable to type 'Observable<number>'.
!!! error TS2322: Type '{}' is not assignable to type 'number'.

View File

@@ -0,0 +1,47 @@
//// [specedNoStackBlown.ts]
// Type definitions for spected 0.7
// Project: https://github.com/25th-floor/spected
// Definitions by: Benjamin Makus <https://github.com/benneq>
// Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped
// TypeScript Version: 2.8
declare function spected<ROOTINPUT, SPEC extends SpecValue<ROOTINPUT, ROOTINPUT> = SpecValue<ROOTINPUT, ROOTINPUT>>(spec: SPEC, input: ROOTINPUT): Result<ROOTINPUT, SPEC>;
type Predicate<INPUT, ROOTINPUT> = (value: INPUT, inputs: ROOTINPUT) => boolean;
type ErrorMsg<INPUT> =
| (string | number | boolean | symbol | null | undefined | object)
| ((value: INPUT, field: string) => any);
export type Spec<INPUT, ROOTINPUT = any> = [Predicate<INPUT, ROOTINPUT>, ErrorMsg<INPUT>];
export type SpecArray<INPUT, ROOTINPUT = any> = Array<Spec<INPUT, ROOTINPUT>>;
export type SpecFunction<INPUT, ROOTINPUT = any> = [INPUT] extends [ReadonlyArray<infer U>]
? (value: INPUT) => ReadonlyArray<SpecArray<U, ROOTINPUT>>
: [INPUT] extends [object]
? (value: INPUT) => SpecObject<INPUT, ROOTINPUT>
: (value: INPUT) => SpecArray<INPUT, ROOTINPUT>;
export type SpecObject<INPUT, ROOTINPUT = any> = Partial<{[key in keyof INPUT]: SpecValue<INPUT[key], ROOTINPUT>}>;
export type SpecValue<INPUT, ROOTINPUT = any> = [INPUT] extends [ReadonlyArray<any>]
? SpecArray<INPUT, ROOTINPUT> | SpecFunction<INPUT, ROOTINPUT>
: [INPUT] extends [object]
? SpecArray<INPUT, ROOTINPUT> | SpecFunction<INPUT, ROOTINPUT> | SpecObject<INPUT, ROOTINPUT>
: SpecArray<INPUT, ROOTINPUT> | SpecFunction<INPUT, ROOTINPUT>;
export type Result<INPUT, SPEC> = {[key in keyof INPUT]: true | any[] | Result<INPUT[key], any>};
export default spected;
//// [specedNoStackBlown.js]
"use strict";
// Type definitions for spected 0.7
// Project: https://github.com/25th-floor/spected
// Definitions by: Benjamin Makus <https://github.com/benneq>
// Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped
// TypeScript Version: 2.8
exports.__esModule = true;
exports["default"] = spected;

View File

@@ -0,0 +1,158 @@
=== tests/cases/compiler/specedNoStackBlown.ts ===
// Type definitions for spected 0.7
// Project: https://github.com/25th-floor/spected
// Definitions by: Benjamin Makus <https://github.com/benneq>
// Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped
// TypeScript Version: 2.8
declare function spected<ROOTINPUT, SPEC extends SpecValue<ROOTINPUT, ROOTINPUT> = SpecValue<ROOTINPUT, ROOTINPUT>>(spec: SPEC, input: ROOTINPUT): Result<ROOTINPUT, SPEC>;
>spected : Symbol(spected, Decl(specedNoStackBlown.ts, 0, 0))
>ROOTINPUT : Symbol(ROOTINPUT, Decl(specedNoStackBlown.ts, 6, 25))
>SPEC : Symbol(SPEC, Decl(specedNoStackBlown.ts, 6, 35))
>SpecValue : Symbol(SpecValue, Decl(specedNoStackBlown.ts, 24, 115))
>ROOTINPUT : Symbol(ROOTINPUT, Decl(specedNoStackBlown.ts, 6, 25))
>ROOTINPUT : Symbol(ROOTINPUT, Decl(specedNoStackBlown.ts, 6, 25))
>SpecValue : Symbol(SpecValue, Decl(specedNoStackBlown.ts, 24, 115))
>ROOTINPUT : Symbol(ROOTINPUT, Decl(specedNoStackBlown.ts, 6, 25))
>ROOTINPUT : Symbol(ROOTINPUT, Decl(specedNoStackBlown.ts, 6, 25))
>spec : Symbol(spec, Decl(specedNoStackBlown.ts, 6, 116))
>SPEC : Symbol(SPEC, Decl(specedNoStackBlown.ts, 6, 35))
>input : Symbol(input, Decl(specedNoStackBlown.ts, 6, 127))
>ROOTINPUT : Symbol(ROOTINPUT, Decl(specedNoStackBlown.ts, 6, 25))
>Result : Symbol(Result, Decl(specedNoStackBlown.ts, 30, 75))
>ROOTINPUT : Symbol(ROOTINPUT, Decl(specedNoStackBlown.ts, 6, 25))
>SPEC : Symbol(SPEC, Decl(specedNoStackBlown.ts, 6, 35))
type Predicate<INPUT, ROOTINPUT> = (value: INPUT, inputs: ROOTINPUT) => boolean;
>Predicate : Symbol(Predicate, Decl(specedNoStackBlown.ts, 6, 171))
>INPUT : Symbol(INPUT, Decl(specedNoStackBlown.ts, 8, 15))
>ROOTINPUT : Symbol(ROOTINPUT, Decl(specedNoStackBlown.ts, 8, 21))
>value : Symbol(value, Decl(specedNoStackBlown.ts, 8, 36))
>INPUT : Symbol(INPUT, Decl(specedNoStackBlown.ts, 8, 15))
>inputs : Symbol(inputs, Decl(specedNoStackBlown.ts, 8, 49))
>ROOTINPUT : Symbol(ROOTINPUT, Decl(specedNoStackBlown.ts, 8, 21))
type ErrorMsg<INPUT> =
>ErrorMsg : Symbol(ErrorMsg, Decl(specedNoStackBlown.ts, 8, 80))
>INPUT : Symbol(INPUT, Decl(specedNoStackBlown.ts, 10, 14))
| (string | number | boolean | symbol | null | undefined | object)
| ((value: INPUT, field: string) => any);
>value : Symbol(value, Decl(specedNoStackBlown.ts, 12, 8))
>INPUT : Symbol(INPUT, Decl(specedNoStackBlown.ts, 10, 14))
>field : Symbol(field, Decl(specedNoStackBlown.ts, 12, 21))
export type Spec<INPUT, ROOTINPUT = any> = [Predicate<INPUT, ROOTINPUT>, ErrorMsg<INPUT>];
>Spec : Symbol(Spec, Decl(specedNoStackBlown.ts, 12, 45))
>INPUT : Symbol(INPUT, Decl(specedNoStackBlown.ts, 14, 17))
>ROOTINPUT : Symbol(ROOTINPUT, Decl(specedNoStackBlown.ts, 14, 23))
>Predicate : Symbol(Predicate, Decl(specedNoStackBlown.ts, 6, 171))
>INPUT : Symbol(INPUT, Decl(specedNoStackBlown.ts, 14, 17))
>ROOTINPUT : Symbol(ROOTINPUT, Decl(specedNoStackBlown.ts, 14, 23))
>ErrorMsg : Symbol(ErrorMsg, Decl(specedNoStackBlown.ts, 8, 80))
>INPUT : Symbol(INPUT, Decl(specedNoStackBlown.ts, 14, 17))
export type SpecArray<INPUT, ROOTINPUT = any> = Array<Spec<INPUT, ROOTINPUT>>;
>SpecArray : Symbol(SpecArray, Decl(specedNoStackBlown.ts, 14, 90))
>INPUT : Symbol(INPUT, Decl(specedNoStackBlown.ts, 16, 22))
>ROOTINPUT : Symbol(ROOTINPUT, Decl(specedNoStackBlown.ts, 16, 28))
>Array : Symbol(Array, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --))
>Spec : Symbol(Spec, Decl(specedNoStackBlown.ts, 12, 45))
>INPUT : Symbol(INPUT, Decl(specedNoStackBlown.ts, 16, 22))
>ROOTINPUT : Symbol(ROOTINPUT, Decl(specedNoStackBlown.ts, 16, 28))
export type SpecFunction<INPUT, ROOTINPUT = any> = [INPUT] extends [ReadonlyArray<infer U>]
>SpecFunction : Symbol(SpecFunction, Decl(specedNoStackBlown.ts, 16, 78))
>INPUT : Symbol(INPUT, Decl(specedNoStackBlown.ts, 18, 25))
>ROOTINPUT : Symbol(ROOTINPUT, Decl(specedNoStackBlown.ts, 18, 31))
>INPUT : Symbol(INPUT, Decl(specedNoStackBlown.ts, 18, 25))
>ReadonlyArray : Symbol(ReadonlyArray, Decl(lib.es5.d.ts, --, --))
>U : Symbol(U, Decl(specedNoStackBlown.ts, 18, 87))
? (value: INPUT) => ReadonlyArray<SpecArray<U, ROOTINPUT>>
>value : Symbol(value, Decl(specedNoStackBlown.ts, 19, 7))
>INPUT : Symbol(INPUT, Decl(specedNoStackBlown.ts, 18, 25))
>ReadonlyArray : Symbol(ReadonlyArray, Decl(lib.es5.d.ts, --, --))
>SpecArray : Symbol(SpecArray, Decl(specedNoStackBlown.ts, 14, 90))
>U : Symbol(U, Decl(specedNoStackBlown.ts, 18, 87))
>ROOTINPUT : Symbol(ROOTINPUT, Decl(specedNoStackBlown.ts, 18, 31))
: [INPUT] extends [object]
>INPUT : Symbol(INPUT, Decl(specedNoStackBlown.ts, 18, 25))
? (value: INPUT) => SpecObject<INPUT, ROOTINPUT>
>value : Symbol(value, Decl(specedNoStackBlown.ts, 21, 11))
>INPUT : Symbol(INPUT, Decl(specedNoStackBlown.ts, 18, 25))
>SpecObject : Symbol(SpecObject, Decl(specedNoStackBlown.ts, 22, 56))
>INPUT : Symbol(INPUT, Decl(specedNoStackBlown.ts, 18, 25))
>ROOTINPUT : Symbol(ROOTINPUT, Decl(specedNoStackBlown.ts, 18, 31))
: (value: INPUT) => SpecArray<INPUT, ROOTINPUT>;
>value : Symbol(value, Decl(specedNoStackBlown.ts, 22, 11))
>INPUT : Symbol(INPUT, Decl(specedNoStackBlown.ts, 18, 25))
>SpecArray : Symbol(SpecArray, Decl(specedNoStackBlown.ts, 14, 90))
>INPUT : Symbol(INPUT, Decl(specedNoStackBlown.ts, 18, 25))
>ROOTINPUT : Symbol(ROOTINPUT, Decl(specedNoStackBlown.ts, 18, 31))
export type SpecObject<INPUT, ROOTINPUT = any> = Partial<{[key in keyof INPUT]: SpecValue<INPUT[key], ROOTINPUT>}>;
>SpecObject : Symbol(SpecObject, Decl(specedNoStackBlown.ts, 22, 56))
>INPUT : Symbol(INPUT, Decl(specedNoStackBlown.ts, 24, 23))
>ROOTINPUT : Symbol(ROOTINPUT, Decl(specedNoStackBlown.ts, 24, 29))
>Partial : Symbol(Partial, Decl(lib.es5.d.ts, --, --))
>key : Symbol(key, Decl(specedNoStackBlown.ts, 24, 59))
>INPUT : Symbol(INPUT, Decl(specedNoStackBlown.ts, 24, 23))
>SpecValue : Symbol(SpecValue, Decl(specedNoStackBlown.ts, 24, 115))
>INPUT : Symbol(INPUT, Decl(specedNoStackBlown.ts, 24, 23))
>key : Symbol(key, Decl(specedNoStackBlown.ts, 24, 59))
>ROOTINPUT : Symbol(ROOTINPUT, Decl(specedNoStackBlown.ts, 24, 29))
export type SpecValue<INPUT, ROOTINPUT = any> = [INPUT] extends [ReadonlyArray<any>]
>SpecValue : Symbol(SpecValue, Decl(specedNoStackBlown.ts, 24, 115))
>INPUT : Symbol(INPUT, Decl(specedNoStackBlown.ts, 26, 22))
>ROOTINPUT : Symbol(ROOTINPUT, Decl(specedNoStackBlown.ts, 26, 28))
>INPUT : Symbol(INPUT, Decl(specedNoStackBlown.ts, 26, 22))
>ReadonlyArray : Symbol(ReadonlyArray, Decl(lib.es5.d.ts, --, --))
? SpecArray<INPUT, ROOTINPUT> | SpecFunction<INPUT, ROOTINPUT>
>SpecArray : Symbol(SpecArray, Decl(specedNoStackBlown.ts, 14, 90))
>INPUT : Symbol(INPUT, Decl(specedNoStackBlown.ts, 26, 22))
>ROOTINPUT : Symbol(ROOTINPUT, Decl(specedNoStackBlown.ts, 26, 28))
>SpecFunction : Symbol(SpecFunction, Decl(specedNoStackBlown.ts, 16, 78))
>INPUT : Symbol(INPUT, Decl(specedNoStackBlown.ts, 26, 22))
>ROOTINPUT : Symbol(ROOTINPUT, Decl(specedNoStackBlown.ts, 26, 28))
: [INPUT] extends [object]
>INPUT : Symbol(INPUT, Decl(specedNoStackBlown.ts, 26, 22))
? SpecArray<INPUT, ROOTINPUT> | SpecFunction<INPUT, ROOTINPUT> | SpecObject<INPUT, ROOTINPUT>
>SpecArray : Symbol(SpecArray, Decl(specedNoStackBlown.ts, 14, 90))
>INPUT : Symbol(INPUT, Decl(specedNoStackBlown.ts, 26, 22))
>ROOTINPUT : Symbol(ROOTINPUT, Decl(specedNoStackBlown.ts, 26, 28))
>SpecFunction : Symbol(SpecFunction, Decl(specedNoStackBlown.ts, 16, 78))
>INPUT : Symbol(INPUT, Decl(specedNoStackBlown.ts, 26, 22))
>ROOTINPUT : Symbol(ROOTINPUT, Decl(specedNoStackBlown.ts, 26, 28))
>SpecObject : Symbol(SpecObject, Decl(specedNoStackBlown.ts, 22, 56))
>INPUT : Symbol(INPUT, Decl(specedNoStackBlown.ts, 26, 22))
>ROOTINPUT : Symbol(ROOTINPUT, Decl(specedNoStackBlown.ts, 26, 28))
: SpecArray<INPUT, ROOTINPUT> | SpecFunction<INPUT, ROOTINPUT>;
>SpecArray : Symbol(SpecArray, Decl(specedNoStackBlown.ts, 14, 90))
>INPUT : Symbol(INPUT, Decl(specedNoStackBlown.ts, 26, 22))
>ROOTINPUT : Symbol(ROOTINPUT, Decl(specedNoStackBlown.ts, 26, 28))
>SpecFunction : Symbol(SpecFunction, Decl(specedNoStackBlown.ts, 16, 78))
>INPUT : Symbol(INPUT, Decl(specedNoStackBlown.ts, 26, 22))
>ROOTINPUT : Symbol(ROOTINPUT, Decl(specedNoStackBlown.ts, 26, 28))
export type Result<INPUT, SPEC> = {[key in keyof INPUT]: true | any[] | Result<INPUT[key], any>};
>Result : Symbol(Result, Decl(specedNoStackBlown.ts, 30, 75))
>INPUT : Symbol(INPUT, Decl(specedNoStackBlown.ts, 32, 19))
>SPEC : Symbol(SPEC, Decl(specedNoStackBlown.ts, 32, 25))
>key : Symbol(key, Decl(specedNoStackBlown.ts, 32, 36))
>INPUT : Symbol(INPUT, Decl(specedNoStackBlown.ts, 32, 19))
>Result : Symbol(Result, Decl(specedNoStackBlown.ts, 30, 75))
>INPUT : Symbol(INPUT, Decl(specedNoStackBlown.ts, 32, 19))
>key : Symbol(key, Decl(specedNoStackBlown.ts, 32, 36))
export default spected;
>spected : Symbol(spected, Decl(specedNoStackBlown.ts, 0, 0))

View File

@@ -0,0 +1,64 @@
=== tests/cases/compiler/specedNoStackBlown.ts ===
// Type definitions for spected 0.7
// Project: https://github.com/25th-floor/spected
// Definitions by: Benjamin Makus <https://github.com/benneq>
// Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped
// TypeScript Version: 2.8
declare function spected<ROOTINPUT, SPEC extends SpecValue<ROOTINPUT, ROOTINPUT> = SpecValue<ROOTINPUT, ROOTINPUT>>(spec: SPEC, input: ROOTINPUT): Result<ROOTINPUT, SPEC>;
>spected : <ROOTINPUT, SPEC extends SpecValue<ROOTINPUT, ROOTINPUT> = SpecValue<ROOTINPUT, ROOTINPUT>>(spec: SPEC, input: ROOTINPUT) => Result<ROOTINPUT, SPEC>
>spec : SPEC
>input : ROOTINPUT
type Predicate<INPUT, ROOTINPUT> = (value: INPUT, inputs: ROOTINPUT) => boolean;
>Predicate : Predicate<INPUT, ROOTINPUT>
>value : INPUT
>inputs : ROOTINPUT
type ErrorMsg<INPUT> =
>ErrorMsg : ErrorMsg<INPUT>
| (string | number | boolean | symbol | null | undefined | object)
>null : null
| ((value: INPUT, field: string) => any);
>value : INPUT
>field : string
export type Spec<INPUT, ROOTINPUT = any> = [Predicate<INPUT, ROOTINPUT>, ErrorMsg<INPUT>];
>Spec : [Predicate<INPUT, ROOTINPUT>, ErrorMsg<INPUT>]
export type SpecArray<INPUT, ROOTINPUT = any> = Array<Spec<INPUT, ROOTINPUT>>;
>SpecArray : [Predicate<INPUT, ROOTINPUT>, ErrorMsg<INPUT>][]
export type SpecFunction<INPUT, ROOTINPUT = any> = [INPUT] extends [ReadonlyArray<infer U>]
>SpecFunction : SpecFunction<INPUT, ROOTINPUT>
? (value: INPUT) => ReadonlyArray<SpecArray<U, ROOTINPUT>>
>value : INPUT
: [INPUT] extends [object]
? (value: INPUT) => SpecObject<INPUT, ROOTINPUT>
>value : INPUT
: (value: INPUT) => SpecArray<INPUT, ROOTINPUT>;
>value : INPUT
export type SpecObject<INPUT, ROOTINPUT = any> = Partial<{[key in keyof INPUT]: SpecValue<INPUT[key], ROOTINPUT>}>;
>SpecObject : Partial<{ [key in keyof INPUT]: SpecValue<INPUT[key], ROOTINPUT>; }>
export type SpecValue<INPUT, ROOTINPUT = any> = [INPUT] extends [ReadonlyArray<any>]
>SpecValue : SpecValue<INPUT, ROOTINPUT>
? SpecArray<INPUT, ROOTINPUT> | SpecFunction<INPUT, ROOTINPUT>
: [INPUT] extends [object]
? SpecArray<INPUT, ROOTINPUT> | SpecFunction<INPUT, ROOTINPUT> | SpecObject<INPUT, ROOTINPUT>
: SpecArray<INPUT, ROOTINPUT> | SpecFunction<INPUT, ROOTINPUT>;
export type Result<INPUT, SPEC> = {[key in keyof INPUT]: true | any[] | Result<INPUT[key], any>};
>Result : Result<INPUT, SPEC>
>true : true
export default spected;
>spected : <ROOTINPUT, SPEC extends SpecValue<ROOTINPUT, ROOTINPUT> = SpecValue<ROOTINPUT, ROOTINPUT>>(spec: SPEC, input: ROOTINPUT) => Result<ROOTINPUT, SPEC>

View File

@@ -62,13 +62,9 @@ tests/cases/compiler/strictFunctionTypesErrors.ts(84,1): error TS2322: Type 'Fun
tests/cases/compiler/strictFunctionTypesErrors.ts(111,1): error TS2322: Type 'Comparer2<Dog>' is not assignable to type 'Comparer2<Animal>'.
Property 'dog' is missing in type 'Animal' but required in type 'Dog'.
tests/cases/compiler/strictFunctionTypesErrors.ts(126,1): error TS2322: Type 'Crate<Dog>' is not assignable to type 'Crate<Animal>'.
Types of property 'onSetItem' are incompatible.
Type '(item: Dog) => void' is not assignable to type '(item: Animal) => void'.
Types of parameters 'item' and 'item' are incompatible.
Type 'Animal' is not assignable to type 'Dog'.
Type 'Animal' is not assignable to type 'Dog'.
tests/cases/compiler/strictFunctionTypesErrors.ts(127,1): error TS2322: Type 'Crate<Animal>' is not assignable to type 'Crate<Dog>'.
Types of property 'item' are incompatible.
Type 'Animal' is not assignable to type 'Dog'.
Type 'Animal' is not assignable to type 'Dog'.
tests/cases/compiler/strictFunctionTypesErrors.ts(133,1): error TS2322: Type '(f: (x: Dog) => Dog) => void' is not assignable to type '(f: (x: Animal) => Animal) => void'.
Types of parameters 'f' and 'f' are incompatible.
Type 'Animal' is not assignable to type 'Dog'.
@@ -308,15 +304,11 @@ tests/cases/compiler/strictFunctionTypesErrors.ts(155,5): error TS2322: Type '(c
animalCrate = dogCrate; // Error
~~~~~~~~~~~
!!! error TS2322: Type 'Crate<Dog>' is not assignable to type 'Crate<Animal>'.
!!! error TS2322: Types of property 'onSetItem' are incompatible.
!!! error TS2322: Type '(item: Dog) => void' is not assignable to type '(item: Animal) => void'.
!!! error TS2322: Types of parameters 'item' and 'item' are incompatible.
!!! error TS2322: Type 'Animal' is not assignable to type 'Dog'.
!!! error TS2322: Type 'Animal' is not assignable to type 'Dog'.
dogCrate = animalCrate; // Error
~~~~~~~~
!!! error TS2322: Type 'Crate<Animal>' is not assignable to type 'Crate<Dog>'.
!!! error TS2322: Types of property 'item' are incompatible.
!!! error TS2322: Type 'Animal' is not assignable to type 'Dog'.
!!! error TS2322: Type 'Animal' is not assignable to type 'Dog'.
// Verify that callback parameters are strictly checked

View File

@@ -1,82 +0,0 @@
tests/cases/compiler/varianceProblingAndZeroOrderIndexSignatureRelationsAlign.ts(63,6): error TS2345: Argument of type 'NeededInfo<ToB<{ initialize: any; }>>' is not assignable to parameter of type 'NeededInfo<{}>'.
Types of property 'ASchema' are incompatible.
Type 'ToA<ToB<{ initialize: any; }>>' is not assignable to type 'ToA<{}>'.
Type '{}' is not assignable to type 'ToB<{ initialize: any; }>'.
tests/cases/compiler/varianceProblingAndZeroOrderIndexSignatureRelationsAlign.ts(66,38): error TS2344: Type 'NeededInfo<ToB<{ initialize: any; }>>' does not satisfy the constraint 'NeededInfo<{}>'.
==== tests/cases/compiler/varianceProblingAndZeroOrderIndexSignatureRelationsAlign.ts (2 errors) ====
type Either<L, A> = Left<L, A> | Right<L, A>;
class Left<L, A> {
readonly _tag: 'Left' = 'Left'
readonly _A!: A
readonly _L!: L
constructor(readonly value: L) {}
/** The given function is applied if this is a `Right` */
map<B>(f: (a: A) => B): Either<L, B> {
return this as any
}
ap<B>(fab: Either<L, (a: A) => B>): Either<L, B> {
return null as any
}
}
class Right<L, A> {
readonly _tag: 'Right' = 'Right'
readonly _A!: A
readonly _L!: L
constructor(readonly value: A) {}
map<B>(f: (a: A) => B): Either<L, B> {
return new Right(f(this.value))
}
ap<B>(fab: Either<L, (a: A) => B>): Either<L, B> {
return null as any;
}
}
class Type<A, O = A, I = unknown> {
readonly _A!: A;
readonly _O!: O;
readonly _I!: I;
constructor(
/** a unique name for this codec */
readonly name: string,
/** a custom type guard */
readonly is: (u: unknown) => u is A,
/** succeeds if a value of type I can be decoded to a value of type A */
readonly validate: (input: I, context: {}[]) => Either<{}[], A>,
/** converts a value of type A to a value of type O */
readonly encode: (a: A) => O
) {}
/** a version of `validate` with a default context */
decode(i: I): Either<{}[], A> { return null as any; }
}
interface Any extends Type<any, any, any> {}
type TypeOf<C extends Any> = C["_A"];
type ToB<S extends any> = { [k in keyof S]: TypeOf<S[k]> };
type ToA<S> = { [k in keyof S]: Type<S[k]> };
type NeededInfo<MyNamespaceSchema = {}> = {
ASchema: ToA<MyNamespaceSchema>;
};
export type MyInfo = NeededInfo<ToB<{ initialize: any }>>;
const tmp1: MyInfo = null!;
function tmp2<N extends NeededInfo>(n: N) {}
tmp2(tmp1); // uncommenting this line removes a type error from a completely unrelated line ??
~~~~
!!! error TS2345: Argument of type 'NeededInfo<ToB<{ initialize: any; }>>' is not assignable to parameter of type 'NeededInfo<{}>'.
!!! error TS2345: Types of property 'ASchema' are incompatible.
!!! error TS2345: Type 'ToA<ToB<{ initialize: any; }>>' is not assignable to type 'ToA<{}>'.
!!! error TS2345: Type '{}' is not assignable to type 'ToB<{ initialize: any; }>'.
!!! related TS2728 tests/cases/compiler/varianceProblingAndZeroOrderIndexSignatureRelationsAlign.ts:59:39: 'initialize' is declared here.
class Server<X extends NeededInfo> {}
export class MyServer extends Server<MyInfo> {} // not assignable error at `MyInfo`
~~~~~~
!!! error TS2344: Type 'NeededInfo<ToB<{ initialize: any; }>>' does not satisfy the constraint 'NeededInfo<{}>'.

View File

@@ -155,7 +155,7 @@ function tmp2<N extends NeededInfo>(n: N) {}
>n : N
tmp2(tmp1); // uncommenting this line removes a type error from a completely unrelated line ??
>tmp2(tmp1) : any
>tmp2(tmp1) : void
>tmp2 : <N extends NeededInfo<{}>>(n: N) => void
>tmp1 : NeededInfo<ToB<{ initialize: any; }>>

View File

@@ -1,79 +0,0 @@
tests/cases/compiler/varianceProblingAndZeroOrderIndexSignatureRelationsAlign2.ts(66,38): error TS2344: Type 'NeededInfo<ToB<{ initialize: any; }>>' does not satisfy the constraint 'NeededInfo<{}>'.
Types of property 'ASchema' are incompatible.
Type 'ToA<ToB<{ initialize: any; }>>' is not assignable to type 'ToA<{}>'.
Type '{}' is not assignable to type 'ToB<{ initialize: any; }>'.
==== tests/cases/compiler/varianceProblingAndZeroOrderIndexSignatureRelationsAlign2.ts (1 errors) ====
type Either<L, A> = Left<L, A> | Right<L, A>;
class Left<L, A> {
readonly _tag: 'Left' = 'Left'
readonly _A!: A
readonly _L!: L
constructor(readonly value: L) {}
/** The given function is applied if this is a `Right` */
map<B>(f: (a: A) => B): Either<L, B> {
return this as any
}
ap<B>(fab: Either<L, (a: A) => B>): Either<L, B> {
return null as any
}
}
class Right<L, A> {
readonly _tag: 'Right' = 'Right'
readonly _A!: A
readonly _L!: L
constructor(readonly value: A) {}
map<B>(f: (a: A) => B): Either<L, B> {
return new Right(f(this.value))
}
ap<B>(fab: Either<L, (a: A) => B>): Either<L, B> {
return null as any;
}
}
class Type<A, O = A, I = unknown> {
readonly _A!: A;
readonly _O!: O;
readonly _I!: I;
constructor(
/** a unique name for this codec */
readonly name: string,
/** a custom type guard */
readonly is: (u: unknown) => u is A,
/** succeeds if a value of type I can be decoded to a value of type A */
readonly validate: (input: I, context: {}[]) => Either<{}[], A>,
/** converts a value of type A to a value of type O */
readonly encode: (a: A) => O
) {}
/** a version of `validate` with a default context */
decode(i: I): Either<{}[], A> { return null as any; }
}
interface Any extends Type<any, any, any> {}
type TypeOf<C extends Any> = C["_A"];
type ToB<S extends any> = { [k in keyof S]: TypeOf<S[k]> };
type ToA<S> = { [k in keyof S]: Type<S[k]> };
type NeededInfo<MyNamespaceSchema = {}> = {
ASchema: ToA<MyNamespaceSchema>;
};
export type MyInfo = NeededInfo<ToB<{ initialize: any }>>;
const tmp1: MyInfo = null!;
function tmp2<N extends NeededInfo>(n: N) {}
// tmp2(tmp1); // uncommenting this line removes a type error from a completely unrelated line ?? (see test 1, needs to behave the same)
class Server<X extends NeededInfo> {}
export class MyServer extends Server<MyInfo> {} // not assignable error at `MyInfo`
~~~~~~
!!! error TS2344: Type 'NeededInfo<ToB<{ initialize: any; }>>' does not satisfy the constraint 'NeededInfo<{}>'.
!!! error TS2344: Types of property 'ASchema' are incompatible.
!!! error TS2344: Type 'ToA<ToB<{ initialize: any; }>>' is not assignable to type 'ToA<{}>'.
!!! error TS2344: Type '{}' is not assignable to type 'ToB<{ initialize: any; }>'.
!!! related TS2728 tests/cases/compiler/varianceProblingAndZeroOrderIndexSignatureRelationsAlign2.ts:59:39: 'initialize' is declared here.

View File

@@ -0,0 +1,12 @@
interface Foo {
a: number;
b: number;
bar: string;
}
interface ObjectContaining<T> {
new (sample: Partial<T>): Partial<T>
}
declare let cafoo: ObjectContaining<{ a: number, foo: number }>;
declare let cfoo: ObjectContaining<Foo>;
cfoo = cafoo;
cafoo = cfoo;

View File

@@ -0,0 +1,35 @@
// Type definitions for spected 0.7
// Project: https://github.com/25th-floor/spected
// Definitions by: Benjamin Makus <https://github.com/benneq>
// Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped
// TypeScript Version: 2.8
declare function spected<ROOTINPUT, SPEC extends SpecValue<ROOTINPUT, ROOTINPUT> = SpecValue<ROOTINPUT, ROOTINPUT>>(spec: SPEC, input: ROOTINPUT): Result<ROOTINPUT, SPEC>;
type Predicate<INPUT, ROOTINPUT> = (value: INPUT, inputs: ROOTINPUT) => boolean;
type ErrorMsg<INPUT> =
| (string | number | boolean | symbol | null | undefined | object)
| ((value: INPUT, field: string) => any);
export type Spec<INPUT, ROOTINPUT = any> = [Predicate<INPUT, ROOTINPUT>, ErrorMsg<INPUT>];
export type SpecArray<INPUT, ROOTINPUT = any> = Array<Spec<INPUT, ROOTINPUT>>;
export type SpecFunction<INPUT, ROOTINPUT = any> = [INPUT] extends [ReadonlyArray<infer U>]
? (value: INPUT) => ReadonlyArray<SpecArray<U, ROOTINPUT>>
: [INPUT] extends [object]
? (value: INPUT) => SpecObject<INPUT, ROOTINPUT>
: (value: INPUT) => SpecArray<INPUT, ROOTINPUT>;
export type SpecObject<INPUT, ROOTINPUT = any> = Partial<{[key in keyof INPUT]: SpecValue<INPUT[key], ROOTINPUT>}>;
export type SpecValue<INPUT, ROOTINPUT = any> = [INPUT] extends [ReadonlyArray<any>]
? SpecArray<INPUT, ROOTINPUT> | SpecFunction<INPUT, ROOTINPUT>
: [INPUT] extends [object]
? SpecArray<INPUT, ROOTINPUT> | SpecFunction<INPUT, ROOTINPUT> | SpecObject<INPUT, ROOTINPUT>
: SpecArray<INPUT, ROOTINPUT> | SpecFunction<INPUT, ROOTINPUT>;
export type Result<INPUT, SPEC> = {[key in keyof INPUT]: true | any[] | Result<INPUT[key], any>};
export default spected;