From a9ad94ab3c35615b344c51e721f77655c225b524 Mon Sep 17 00:00:00 2001 From: Wesley Wigham Date: Fri, 8 Mar 2019 15:33:12 -0800 Subject: [PATCH] Conditional type simplifications & Globally cached conditional type instances (#29437) * Introduce simpliciations for extract/exclude-like conditional types and fix restrictive instantiations * Add test for the common simplifications * unify true branch constraint generation logic and true branch simplification * Use identical check on instantiated types * Add late-instantiate conditionals to test * Globally cache conditional type instantiations ala indexed access types * Handle `any` simplifications * Factor empty intersection check into function * Modifify conditional type constraints to better handle single-branch `any` and restrictive type parameters * Add test case motivating prior commit * Fix lint * Factor logic into worker vs cacheing function * Remove now unneeded casts --- src/compiler/checker.ts | 97 ++++- .../baselines/reference/conditionalTypes1.js | 4 +- .../reference/conditionalTypes1.types | 20 +- .../reference/conditionalTypes2.types | 6 +- .../conditionalTypesSimplifyWhenTrivial.js | 100 +++++ ...onditionalTypesSimplifyWhenTrivial.symbols | 245 ++++++++++++ .../conditionalTypesSimplifyWhenTrivial.types | 167 ++++++++ .../reference/propTypeValidatorInference.js | 121 ++++++ .../propTypeValidatorInference.symbols | 366 ++++++++++++++++++ .../propTypeValidatorInference.types | 301 ++++++++++++++ .../conditionalTypesSimplifyWhenTrivial.ts | 65 ++++ .../compiler/propTypeValidatorInference.ts | 89 +++++ 12 files changed, 1554 insertions(+), 27 deletions(-) create mode 100644 tests/baselines/reference/conditionalTypesSimplifyWhenTrivial.js create mode 100644 tests/baselines/reference/conditionalTypesSimplifyWhenTrivial.symbols create mode 100644 tests/baselines/reference/conditionalTypesSimplifyWhenTrivial.types create mode 100644 tests/baselines/reference/propTypeValidatorInference.js create mode 100644 tests/baselines/reference/propTypeValidatorInference.symbols create mode 100644 tests/baselines/reference/propTypeValidatorInference.types create mode 100644 tests/cases/compiler/conditionalTypesSimplifyWhenTrivial.ts create mode 100644 tests/cases/compiler/propTypeValidatorInference.ts diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index ec9e181c05211..ec544ea0950d0 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -387,6 +387,7 @@ namespace ts { const intersectionTypes = createMap(); const literalTypes = createMap(); const indexedAccessTypes = createMap(); + const conditionalTypes = createMap(); const evolvingArrayTypes: EvolvingArrayType[] = []; const undefinedProperties = createMap() as UnderscoreEscapedMap; @@ -7461,15 +7462,25 @@ namespace ts { return baseConstraint && baseConstraint !== type ? baseConstraint : undefined; } + function getDefaultConstraintOfTrueBranchOfConditionalType(root: ConditionalRoot, combinedMapper: TypeMapper | undefined, mapper: TypeMapper | undefined) { + const rootTrueType = root.trueType; + const rootTrueConstraint = !(rootTrueType.flags & TypeFlags.Substitution) + ? rootTrueType + : instantiateType(((rootTrueType).substitute), combinedMapper || mapper).flags & TypeFlags.AnyOrUnknown + ? (rootTrueType).typeVariable + : getIntersectionType([(rootTrueType).substitute, (rootTrueType).typeVariable]); + return instantiateType(rootTrueConstraint, combinedMapper || mapper); + } + function getDefaultConstraintOfConditionalType(type: ConditionalType) { if (!type.resolvedDefaultConstraint) { - const rootTrueType = type.root.trueType; - const rootTrueConstraint = !(rootTrueType.flags & TypeFlags.Substitution) - ? rootTrueType - : ((rootTrueType).substitute).flags & TypeFlags.AnyOrUnknown - ? (rootTrueType).typeVariable - : getIntersectionType([(rootTrueType).substitute, (rootTrueType).typeVariable]); - type.resolvedDefaultConstraint = getUnionType([instantiateType(rootTrueConstraint, type.combinedMapper || type.mapper), getFalseTypeFromConditionalType(type)]); + // An `any` branch of a conditional type would normally be viral - specifically, without special handling here, + // a conditional type with a single branch of type `any` would be assignable to anything, since it's constraint would simplify to + // just `any`. This result is _usually_ unwanted - so instead here we elide an `any` branch from the constraint type, + // in effect treating `any` like `never` rather than `unknown` in this location. + const trueConstraint = getDefaultConstraintOfTrueBranchOfConditionalType(type.root, type.combinedMapper, type.mapper); + const falseConstraint = getFalseTypeFromConditionalType(type); + type.resolvedDefaultConstraint = isTypeAny(trueConstraint) ? falseConstraint : isTypeAny(falseConstraint) ? trueConstraint : getUnionType([trueConstraint, falseConstraint]); } return type.resolvedDefaultConstraint; } @@ -7480,7 +7491,13 @@ namespace ts { // with its constraint. We do this because if the constraint is a union type it will be distributed // over the conditional type and possibly reduced. For example, 'T extends undefined ? never : T' // removes 'undefined' from T. - if (type.root.isDistributive) { + // We skip returning a distributive constraint for a restrictive instantiation of a conditional type + // as the constraint for all type params (check type included) have been replace with `unknown`, which + // is going to produce even more false positive/negative results than the distribute constraint already does. + // Please note: the distributive constraint is a kludge for emulating what a negated type could to do filter + // a union - once negated types exist and are applied to the conditional false branch, this "constraint" + // likely doesn't need to exist. + if (type.root.isDistributive && type.restrictiveInstantiation !== type) { const simplified = getSimplifiedType(type.checkType); const constraint = simplified === type.checkType ? getConstraintOfType(simplified) : simplified; if (constraint && constraint !== type.checkType) { @@ -10089,12 +10106,50 @@ namespace ts { return type.flags & TypeFlags.Substitution ? (type).typeVariable : type; } + /** + * Invokes union simplification logic to determine if an intersection is considered empty as a union constituent + */ + function isIntersectionEmpty(type1: Type, type2: Type) { + return !!(getUnionType([intersectTypes(type1, type2), neverType]).flags & TypeFlags.Never); + } + function getConditionalType(root: ConditionalRoot, mapper: TypeMapper | undefined): Type { const checkType = instantiateType(root.checkType, mapper); const extendsType = instantiateType(root.extendsType, mapper); if (checkType === wildcardType || extendsType === wildcardType) { return wildcardType; } + const trueType = instantiateType(root.trueType, mapper); + const falseType = instantiateType(root.falseType, mapper); + const instantiationId = `${root.isDistributive ? "d" : ""}${getTypeId(checkType)}>${getTypeId(extendsType)}?${getTypeId(trueType)}:${getTypeId(falseType)}`; + const result = conditionalTypes.get(instantiationId); + if (result) { + return result; + } + const newResult = getConditionalTypeWorker(root, mapper, checkType, extendsType, trueType, falseType); + conditionalTypes.set(instantiationId, newResult); + return newResult; + } + + function getConditionalTypeWorker(root: ConditionalRoot, mapper: TypeMapper | undefined, checkType: Type, extendsType: Type, trueType: Type, falseType: Type) { + // Simplifications for types of the form `T extends U ? T : never` and `T extends U ? never : T`. + if (falseType.flags & TypeFlags.Never && isTypeIdenticalTo(getActualTypeVariable(trueType), getActualTypeVariable(checkType))) { + if (checkType.flags & TypeFlags.Any || isTypeAssignableTo(getRestrictiveInstantiation(checkType), getRestrictiveInstantiation(extendsType))) { // Always true + return getDefaultConstraintOfTrueBranchOfConditionalType(root, /*combinedMapper*/ undefined, mapper); + } + else if (isIntersectionEmpty(checkType, extendsType)) { // Always false + return neverType; + } + } + else if (trueType.flags & TypeFlags.Never && isTypeIdenticalTo(getActualTypeVariable(falseType), getActualTypeVariable(checkType))) { + if (!(checkType.flags & TypeFlags.Any) && isTypeAssignableTo(getRestrictiveInstantiation(checkType), getRestrictiveInstantiation(extendsType))) { // Always true + return neverType; + } + else if (checkType.flags & TypeFlags.Any || isIntersectionEmpty(checkType, extendsType)) { // Always false + return falseType; // TODO: Intersect negated `extends` type here + } + } + const checkTypeInstantiable = maybeTypeOfKind(checkType, TypeFlags.Instantiable | TypeFlags.GenericMappedType); let combinedMapper: TypeMapper | undefined; if (root.inferTypeParameters) { @@ -10112,18 +10167,18 @@ namespace ts { // We attempt to resolve the conditional type only when the check and extends types are non-generic if (!checkTypeInstantiable && !maybeTypeOfKind(inferredExtendsType, TypeFlags.Instantiable | TypeFlags.GenericMappedType)) { if (inferredExtendsType.flags & TypeFlags.AnyOrUnknown) { - return instantiateType(root.trueType, mapper); + return trueType; } // Return union of trueType and falseType for 'any' since it matches anything if (checkType.flags & TypeFlags.Any) { - return getUnionType([instantiateType(root.trueType, combinedMapper || mapper), instantiateType(root.falseType, mapper)]); + return getUnionType([instantiateType(root.trueType, combinedMapper || mapper), falseType]); } // Return falseType for a definitely false extends check. We check an instantiations of the two // types with type parameters mapped to the wildcard type, the most permissive instantiations // possible (the wildcard type is assignable to and from all types). If those are not related, // then no instantiations will be and we can just return the false branch type. if (!isTypeAssignableTo(getPermissiveInstantiation(checkType), getPermissiveInstantiation(inferredExtendsType))) { - return instantiateType(root.falseType, mapper); + return falseType; } // Return trueType for a definitely true extends check. We check instantiations of the two // types with type parameters mapped to their restrictive form, i.e. a form of the type parameter @@ -10142,6 +10197,10 @@ namespace ts { result.extendsType = extendsType; result.mapper = mapper; result.combinedMapper = combinedMapper; + if (!combinedMapper) { + result.resolvedTrueType = trueType; + result.resolvedFalseType = falseType; + } result.aliasSymbol = root.aliasSymbol; result.aliasTypeArguments = instantiateTypes(root.aliasTypeArguments, mapper!); // TODO: GH#18217 return result; @@ -11132,8 +11191,20 @@ namespace ts { } function getRestrictiveInstantiation(type: Type) { - return type.flags & (TypeFlags.Primitive | TypeFlags.AnyOrUnknown | TypeFlags.Never) ? type : - type.restrictiveInstantiation || (type.restrictiveInstantiation = instantiateType(type, restrictiveMapper)); + if (type.flags & (TypeFlags.Primitive | TypeFlags.AnyOrUnknown | TypeFlags.Never)) { + return type; + } + if (type.restrictiveInstantiation) { + return type.restrictiveInstantiation; + } + type.restrictiveInstantiation = instantiateType(type, restrictiveMapper); + // We set the following so we don't attempt to set the restrictive instance of a restrictive instance + // which is redundant - we'll produce new type identities, but all type params have already been mapped. + // This also gives us a way to detect restrictive instances upon comparisons and _disable_ the "distributeive constraint" + // assignability check for them, which is distinctly unsafe, as once you have a restrctive instance, all the type parameters + // are constrained to `unknown` and produce tons of false positives/negatives! + type.restrictiveInstantiation.restrictiveInstantiation = type.restrictiveInstantiation; + return type.restrictiveInstantiation; } function instantiateIndexInfo(info: IndexInfo | undefined, mapper: TypeMapper): IndexInfo | undefined { diff --git a/tests/baselines/reference/conditionalTypes1.js b/tests/baselines/reference/conditionalTypes1.js index 7ce19ce17e70c..b592bd33d10e8 100644 --- a/tests/baselines/reference/conditionalTypes1.js +++ b/tests/baselines/reference/conditionalTypes1.js @@ -509,6 +509,8 @@ declare function f5(p: K): Extract; declare let x0: { k: "a"; +} & { + k: "a"; a: number; }; declare type OptionsOfKind = Extract; declare type T83 = Eq2; declare type Foo = T extends string ? boolean : number; declare type Bar = T extends string ? boolean : number; -declare const convert: (value: Foo) => Bar; +declare const convert: (value: Foo) => Foo; declare type Baz = Foo; declare const convert2: (value: Foo) => Foo; declare function f31(): void; diff --git a/tests/baselines/reference/conditionalTypes1.types b/tests/baselines/reference/conditionalTypes1.types index 08fdb4b2f291c..8cca94f0a1021 100644 --- a/tests/baselines/reference/conditionalTypes1.types +++ b/tests/baselines/reference/conditionalTypes1.types @@ -9,7 +9,7 @@ type T02 = Exclude void), Function>; // string | numbe >T02 : string | number type T03 = Extract void), Function>; // () => void ->T03 : () => void +>T03 : Function & (() => void) type T04 = NonNullable; // string | number >T04 : string | number @@ -113,7 +113,7 @@ type T10 = Exclude; // { k: "c", c: boolean } >k : "a" | "b" type T11 = Extract; // { k: "a", a: number } | { k: "b", b: string } ->T11 : { k: "a"; a: number; } | { k: "b"; b: string; } +>T11 : ({ k: "a" | "b"; } & { k: "a"; a: number; }) | ({ k: "a" | "b"; } & { k: "b"; b: string; }) >k : "a" | "b" type T12 = Exclude; // { k: "c", c: boolean } @@ -122,7 +122,7 @@ type T12 = Exclude; // { k: "c", c: boolean } >k : "b" type T13 = Extract; // { k: "a", a: number } | { k: "b", b: string } ->T13 : { k: "a"; a: number; } | { k: "b"; b: string; } +>T13 : ({ k: "a"; } & { k: "a"; a: number; }) | ({ k: "b"; } & { k: "a"; a: number; }) | ({ k: "a"; } & { k: "b"; b: string; }) | ({ k: "b"; } & { k: "b"; b: string; }) >k : "a" >k : "b" @@ -140,8 +140,8 @@ declare function f5(p: K): Extractk : K let x0 = f5("a"); // { k: "a", a: number } ->x0 : { k: "a"; a: number; } ->f5("a") : { k: "a"; a: number; } +>x0 : { k: "a"; } & { k: "a"; a: number; } +>f5("a") : { k: "a"; } & { k: "a"; a: number; } >f5 : (p: K) => Extract >"a" : "a" @@ -150,13 +150,13 @@ type OptionsOfKind = Extract; >k : K type T16 = OptionsOfKind<"a" | "b">; // { k: "a", a: number } | { k: "b", b: string } ->T16 : { k: "a"; a: number; } | { k: "b"; b: string; } +>T16 : ({ k: "a" | "b"; } & { k: "a"; a: number; }) | ({ k: "a" | "b"; } & { k: "b"; b: string; }) type Select = Extract; >Select : Extract type T17 = Select; // // { k: "a", a: number } | { k: "b", b: string } ->T17 : { k: "a"; a: number; } | { k: "b"; b: string; } +>T17 : ({ k: "a" | "b"; } & { k: "a"; a: number; }) | ({ k: "a" | "b"; } & { k: "b"; b: string; }) type TypeName = >TypeName : TypeName @@ -779,8 +779,8 @@ type Bar = T extends string ? boolean : number; >Bar : Bar const convert = (value: Foo): Bar => value; ->convert : (value: Foo) => Bar ->(value: Foo): Bar => value : (value: Foo) => Bar +>convert : (value: Foo) => Foo +>(value: Foo): Bar => value : (value: Foo) => Foo >value : Foo >value : Foo @@ -832,7 +832,7 @@ function f33() { >T1 : Foo type T2 = Bar; ->T2 : Bar +>T2 : Foo var z: T1; >z : Foo diff --git a/tests/baselines/reference/conditionalTypes2.types b/tests/baselines/reference/conditionalTypes2.types index aac6ba47475c6..7113ccc2be809 100644 --- a/tests/baselines/reference/conditionalTypes2.types +++ b/tests/baselines/reference/conditionalTypes2.types @@ -130,14 +130,14 @@ function f12(x: string | (() => string) | undefined) { >x : string | (() => string) | undefined const f = getFunction(x); // () => string ->f : () => string ->getFunction(x) : () => string +>f : Function & (() => string) +>getFunction(x) : Function & (() => string) >getFunction : (item: T) => Extract >x : string | (() => string) | undefined f(); >f() : string ->f : () => string +>f : Function & (() => string) } type Foo = { foo: string }; diff --git a/tests/baselines/reference/conditionalTypesSimplifyWhenTrivial.js b/tests/baselines/reference/conditionalTypesSimplifyWhenTrivial.js new file mode 100644 index 0000000000000..41b9476db8828 --- /dev/null +++ b/tests/baselines/reference/conditionalTypesSimplifyWhenTrivial.js @@ -0,0 +1,100 @@ +//// [conditionalTypesSimplifyWhenTrivial.ts] +const fn1 = ( + params: Pick>, +): Params => params; + +function fn2(x: Exclude) { + var y: T = x; + x = y; +} + +const fn3 = ( + params: Pick>, +): Params => params; + +function fn4(x: Extract) { + var y: T = x; + x = y; +} + +declare var x: Extract; // Should be `numebr | string` and not `any` + +type ExtractWithDefault = T extends U ? T : D; + +type ExcludeWithDefault = T extends U ? D : T; + +const fn5 = ( + params: Pick>, +): Params => params; + +function fn6(x: ExcludeWithDefault) { + var y: T = x; + x = y; +} + +const fn7 = ( + params: Pick>, +): Params => params; + +function fn8(x: ExtractWithDefault) { + var y: T = x; + x = y; +} + +type TemplatedConditional = TCheck extends TExtends ? TTrue : TFalse; + +const fn9 = ( + params: Pick>, +): Params => params; + +function fn10(x: TemplatedConditional) { + var y: T = x; + x = y; +} + +const fn11 = ( + params: Pick>, +): Params => params; + +function fn12(x: TemplatedConditional) { + var y: T = x; + x = y; +} + +declare var z: any; +const zee = z!!!; // since x is `any`, `x extends null | undefined` should be both true and false - and thus yield `any` + + +//// [conditionalTypesSimplifyWhenTrivial.js] +"use strict"; +var fn1 = function (params) { return params; }; +function fn2(x) { + var y = x; + x = y; +} +var fn3 = function (params) { return params; }; +function fn4(x) { + var y = x; + x = y; +} +var fn5 = function (params) { return params; }; +function fn6(x) { + var y = x; + x = y; +} +var fn7 = function (params) { return params; }; +function fn8(x) { + var y = x; + x = y; +} +var fn9 = function (params) { return params; }; +function fn10(x) { + var y = x; + x = y; +} +var fn11 = function (params) { return params; }; +function fn12(x) { + var y = x; + x = y; +} +var zee = z; // since x is `any`, `x extends null | undefined` should be both true and false - and thus yield `any` diff --git a/tests/baselines/reference/conditionalTypesSimplifyWhenTrivial.symbols b/tests/baselines/reference/conditionalTypesSimplifyWhenTrivial.symbols new file mode 100644 index 0000000000000..f8b99f9eb6ae2 --- /dev/null +++ b/tests/baselines/reference/conditionalTypesSimplifyWhenTrivial.symbols @@ -0,0 +1,245 @@ +=== tests/cases/compiler/conditionalTypesSimplifyWhenTrivial.ts === +const fn1 = ( +>fn1 : Symbol(fn1, Decl(conditionalTypesSimplifyWhenTrivial.ts, 0, 5)) +>Params : Symbol(Params, Decl(conditionalTypesSimplifyWhenTrivial.ts, 0, 13)) + + params: Pick>, +>params : Symbol(params, Decl(conditionalTypesSimplifyWhenTrivial.ts, 0, 21)) +>Pick : Symbol(Pick, Decl(lib.es5.d.ts, --, --)) +>Params : Symbol(Params, Decl(conditionalTypesSimplifyWhenTrivial.ts, 0, 13)) +>Exclude : Symbol(Exclude, Decl(lib.es5.d.ts, --, --)) +>Params : Symbol(Params, Decl(conditionalTypesSimplifyWhenTrivial.ts, 0, 13)) + +): Params => params; +>Params : Symbol(Params, Decl(conditionalTypesSimplifyWhenTrivial.ts, 0, 13)) +>params : Symbol(params, Decl(conditionalTypesSimplifyWhenTrivial.ts, 0, 21)) + +function fn2(x: Exclude) { +>fn2 : Symbol(fn2, Decl(conditionalTypesSimplifyWhenTrivial.ts, 2, 20)) +>T : Symbol(T, Decl(conditionalTypesSimplifyWhenTrivial.ts, 4, 13)) +>x : Symbol(x, Decl(conditionalTypesSimplifyWhenTrivial.ts, 4, 16)) +>Exclude : Symbol(Exclude, Decl(lib.es5.d.ts, --, --)) +>T : Symbol(T, Decl(conditionalTypesSimplifyWhenTrivial.ts, 4, 13)) + + var y: T = x; +>y : Symbol(y, Decl(conditionalTypesSimplifyWhenTrivial.ts, 5, 7)) +>T : Symbol(T, Decl(conditionalTypesSimplifyWhenTrivial.ts, 4, 13)) +>x : Symbol(x, Decl(conditionalTypesSimplifyWhenTrivial.ts, 4, 16)) + + x = y; +>x : Symbol(x, Decl(conditionalTypesSimplifyWhenTrivial.ts, 4, 16)) +>y : Symbol(y, Decl(conditionalTypesSimplifyWhenTrivial.ts, 5, 7)) +} + +const fn3 = ( +>fn3 : Symbol(fn3, Decl(conditionalTypesSimplifyWhenTrivial.ts, 9, 5)) +>Params : Symbol(Params, Decl(conditionalTypesSimplifyWhenTrivial.ts, 9, 13)) + + params: Pick>, +>params : Symbol(params, Decl(conditionalTypesSimplifyWhenTrivial.ts, 9, 21)) +>Pick : Symbol(Pick, Decl(lib.es5.d.ts, --, --)) +>Params : Symbol(Params, Decl(conditionalTypesSimplifyWhenTrivial.ts, 9, 13)) +>Extract : Symbol(Extract, Decl(lib.es5.d.ts, --, --)) +>Params : Symbol(Params, Decl(conditionalTypesSimplifyWhenTrivial.ts, 9, 13)) +>Params : Symbol(Params, Decl(conditionalTypesSimplifyWhenTrivial.ts, 9, 13)) + +): Params => params; +>Params : Symbol(Params, Decl(conditionalTypesSimplifyWhenTrivial.ts, 9, 13)) +>params : Symbol(params, Decl(conditionalTypesSimplifyWhenTrivial.ts, 9, 21)) + +function fn4(x: Extract) { +>fn4 : Symbol(fn4, Decl(conditionalTypesSimplifyWhenTrivial.ts, 11, 20)) +>T : Symbol(T, Decl(conditionalTypesSimplifyWhenTrivial.ts, 13, 13)) +>x : Symbol(x, Decl(conditionalTypesSimplifyWhenTrivial.ts, 13, 16)) +>Extract : Symbol(Extract, Decl(lib.es5.d.ts, --, --)) +>T : Symbol(T, Decl(conditionalTypesSimplifyWhenTrivial.ts, 13, 13)) +>T : Symbol(T, Decl(conditionalTypesSimplifyWhenTrivial.ts, 13, 13)) + + var y: T = x; +>y : Symbol(y, Decl(conditionalTypesSimplifyWhenTrivial.ts, 14, 7)) +>T : Symbol(T, Decl(conditionalTypesSimplifyWhenTrivial.ts, 13, 13)) +>x : Symbol(x, Decl(conditionalTypesSimplifyWhenTrivial.ts, 13, 16)) + + x = y; +>x : Symbol(x, Decl(conditionalTypesSimplifyWhenTrivial.ts, 13, 16)) +>y : Symbol(y, Decl(conditionalTypesSimplifyWhenTrivial.ts, 14, 7)) +} + +declare var x: Extract; // Should be `numebr | string` and not `any` +>x : Symbol(x, Decl(conditionalTypesSimplifyWhenTrivial.ts, 18, 11)) +>Extract : Symbol(Extract, Decl(lib.es5.d.ts, --, --)) + +type ExtractWithDefault = T extends U ? T : D; +>ExtractWithDefault : Symbol(ExtractWithDefault, Decl(conditionalTypesSimplifyWhenTrivial.ts, 18, 45)) +>T : Symbol(T, Decl(conditionalTypesSimplifyWhenTrivial.ts, 20, 24)) +>U : Symbol(U, Decl(conditionalTypesSimplifyWhenTrivial.ts, 20, 26)) +>D : Symbol(D, Decl(conditionalTypesSimplifyWhenTrivial.ts, 20, 29)) +>T : Symbol(T, Decl(conditionalTypesSimplifyWhenTrivial.ts, 20, 24)) +>U : Symbol(U, Decl(conditionalTypesSimplifyWhenTrivial.ts, 20, 26)) +>T : Symbol(T, Decl(conditionalTypesSimplifyWhenTrivial.ts, 20, 24)) +>D : Symbol(D, Decl(conditionalTypesSimplifyWhenTrivial.ts, 20, 29)) + +type ExcludeWithDefault = T extends U ? D : T; +>ExcludeWithDefault : Symbol(ExcludeWithDefault, Decl(conditionalTypesSimplifyWhenTrivial.ts, 20, 63)) +>T : Symbol(T, Decl(conditionalTypesSimplifyWhenTrivial.ts, 22, 24)) +>U : Symbol(U, Decl(conditionalTypesSimplifyWhenTrivial.ts, 22, 26)) +>D : Symbol(D, Decl(conditionalTypesSimplifyWhenTrivial.ts, 22, 29)) +>T : Symbol(T, Decl(conditionalTypesSimplifyWhenTrivial.ts, 22, 24)) +>U : Symbol(U, Decl(conditionalTypesSimplifyWhenTrivial.ts, 22, 26)) +>D : Symbol(D, Decl(conditionalTypesSimplifyWhenTrivial.ts, 22, 29)) +>T : Symbol(T, Decl(conditionalTypesSimplifyWhenTrivial.ts, 22, 24)) + +const fn5 = ( +>fn5 : Symbol(fn5, Decl(conditionalTypesSimplifyWhenTrivial.ts, 24, 5)) +>Params : Symbol(Params, Decl(conditionalTypesSimplifyWhenTrivial.ts, 24, 13)) + + params: Pick>, +>params : Symbol(params, Decl(conditionalTypesSimplifyWhenTrivial.ts, 24, 21)) +>Pick : Symbol(Pick, Decl(lib.es5.d.ts, --, --)) +>Params : Symbol(Params, Decl(conditionalTypesSimplifyWhenTrivial.ts, 24, 13)) +>ExcludeWithDefault : Symbol(ExcludeWithDefault, Decl(conditionalTypesSimplifyWhenTrivial.ts, 20, 63)) +>Params : Symbol(Params, Decl(conditionalTypesSimplifyWhenTrivial.ts, 24, 13)) + +): Params => params; +>Params : Symbol(Params, Decl(conditionalTypesSimplifyWhenTrivial.ts, 24, 13)) +>params : Symbol(params, Decl(conditionalTypesSimplifyWhenTrivial.ts, 24, 21)) + +function fn6(x: ExcludeWithDefault) { +>fn6 : Symbol(fn6, Decl(conditionalTypesSimplifyWhenTrivial.ts, 26, 20)) +>T : Symbol(T, Decl(conditionalTypesSimplifyWhenTrivial.ts, 28, 13)) +>x : Symbol(x, Decl(conditionalTypesSimplifyWhenTrivial.ts, 28, 16)) +>ExcludeWithDefault : Symbol(ExcludeWithDefault, Decl(conditionalTypesSimplifyWhenTrivial.ts, 20, 63)) +>T : Symbol(T, Decl(conditionalTypesSimplifyWhenTrivial.ts, 28, 13)) + + var y: T = x; +>y : Symbol(y, Decl(conditionalTypesSimplifyWhenTrivial.ts, 29, 7)) +>T : Symbol(T, Decl(conditionalTypesSimplifyWhenTrivial.ts, 28, 13)) +>x : Symbol(x, Decl(conditionalTypesSimplifyWhenTrivial.ts, 28, 16)) + + x = y; +>x : Symbol(x, Decl(conditionalTypesSimplifyWhenTrivial.ts, 28, 16)) +>y : Symbol(y, Decl(conditionalTypesSimplifyWhenTrivial.ts, 29, 7)) +} + +const fn7 = ( +>fn7 : Symbol(fn7, Decl(conditionalTypesSimplifyWhenTrivial.ts, 33, 5)) +>Params : Symbol(Params, Decl(conditionalTypesSimplifyWhenTrivial.ts, 33, 13)) + + params: Pick>, +>params : Symbol(params, Decl(conditionalTypesSimplifyWhenTrivial.ts, 33, 21)) +>Pick : Symbol(Pick, Decl(lib.es5.d.ts, --, --)) +>Params : Symbol(Params, Decl(conditionalTypesSimplifyWhenTrivial.ts, 33, 13)) +>ExtractWithDefault : Symbol(ExtractWithDefault, Decl(conditionalTypesSimplifyWhenTrivial.ts, 18, 45)) +>Params : Symbol(Params, Decl(conditionalTypesSimplifyWhenTrivial.ts, 33, 13)) +>Params : Symbol(Params, Decl(conditionalTypesSimplifyWhenTrivial.ts, 33, 13)) + +): Params => params; +>Params : Symbol(Params, Decl(conditionalTypesSimplifyWhenTrivial.ts, 33, 13)) +>params : Symbol(params, Decl(conditionalTypesSimplifyWhenTrivial.ts, 33, 21)) + +function fn8(x: ExtractWithDefault) { +>fn8 : Symbol(fn8, Decl(conditionalTypesSimplifyWhenTrivial.ts, 35, 20)) +>T : Symbol(T, Decl(conditionalTypesSimplifyWhenTrivial.ts, 37, 13)) +>x : Symbol(x, Decl(conditionalTypesSimplifyWhenTrivial.ts, 37, 16)) +>ExtractWithDefault : Symbol(ExtractWithDefault, Decl(conditionalTypesSimplifyWhenTrivial.ts, 18, 45)) +>T : Symbol(T, Decl(conditionalTypesSimplifyWhenTrivial.ts, 37, 13)) +>T : Symbol(T, Decl(conditionalTypesSimplifyWhenTrivial.ts, 37, 13)) + + var y: T = x; +>y : Symbol(y, Decl(conditionalTypesSimplifyWhenTrivial.ts, 38, 7)) +>T : Symbol(T, Decl(conditionalTypesSimplifyWhenTrivial.ts, 37, 13)) +>x : Symbol(x, Decl(conditionalTypesSimplifyWhenTrivial.ts, 37, 16)) + + x = y; +>x : Symbol(x, Decl(conditionalTypesSimplifyWhenTrivial.ts, 37, 16)) +>y : Symbol(y, Decl(conditionalTypesSimplifyWhenTrivial.ts, 38, 7)) +} + +type TemplatedConditional = TCheck extends TExtends ? TTrue : TFalse; +>TemplatedConditional : Symbol(TemplatedConditional, Decl(conditionalTypesSimplifyWhenTrivial.ts, 40, 1)) +>TCheck : Symbol(TCheck, Decl(conditionalTypesSimplifyWhenTrivial.ts, 42, 26)) +>TExtends : Symbol(TExtends, Decl(conditionalTypesSimplifyWhenTrivial.ts, 42, 33)) +>TTrue : Symbol(TTrue, Decl(conditionalTypesSimplifyWhenTrivial.ts, 42, 43)) +>TFalse : Symbol(TFalse, Decl(conditionalTypesSimplifyWhenTrivial.ts, 42, 50)) +>TCheck : Symbol(TCheck, Decl(conditionalTypesSimplifyWhenTrivial.ts, 42, 26)) +>TExtends : Symbol(TExtends, Decl(conditionalTypesSimplifyWhenTrivial.ts, 42, 33)) +>TTrue : Symbol(TTrue, Decl(conditionalTypesSimplifyWhenTrivial.ts, 42, 43)) +>TFalse : Symbol(TFalse, Decl(conditionalTypesSimplifyWhenTrivial.ts, 42, 50)) + +const fn9 = ( +>fn9 : Symbol(fn9, Decl(conditionalTypesSimplifyWhenTrivial.ts, 44, 5)) +>Params : Symbol(Params, Decl(conditionalTypesSimplifyWhenTrivial.ts, 44, 13)) + + params: Pick>, +>params : Symbol(params, Decl(conditionalTypesSimplifyWhenTrivial.ts, 44, 21)) +>Pick : Symbol(Pick, Decl(lib.es5.d.ts, --, --)) +>Params : Symbol(Params, Decl(conditionalTypesSimplifyWhenTrivial.ts, 44, 13)) +>TemplatedConditional : Symbol(TemplatedConditional, Decl(conditionalTypesSimplifyWhenTrivial.ts, 40, 1)) +>Params : Symbol(Params, Decl(conditionalTypesSimplifyWhenTrivial.ts, 44, 13)) +>Params : Symbol(Params, Decl(conditionalTypesSimplifyWhenTrivial.ts, 44, 13)) + +): Params => params; +>Params : Symbol(Params, Decl(conditionalTypesSimplifyWhenTrivial.ts, 44, 13)) +>params : Symbol(params, Decl(conditionalTypesSimplifyWhenTrivial.ts, 44, 21)) + +function fn10(x: TemplatedConditional) { +>fn10 : Symbol(fn10, Decl(conditionalTypesSimplifyWhenTrivial.ts, 46, 20)) +>T : Symbol(T, Decl(conditionalTypesSimplifyWhenTrivial.ts, 48, 14)) +>x : Symbol(x, Decl(conditionalTypesSimplifyWhenTrivial.ts, 48, 17)) +>TemplatedConditional : Symbol(TemplatedConditional, Decl(conditionalTypesSimplifyWhenTrivial.ts, 40, 1)) +>T : Symbol(T, Decl(conditionalTypesSimplifyWhenTrivial.ts, 48, 14)) +>T : Symbol(T, Decl(conditionalTypesSimplifyWhenTrivial.ts, 48, 14)) + + var y: T = x; +>y : Symbol(y, Decl(conditionalTypesSimplifyWhenTrivial.ts, 49, 7)) +>T : Symbol(T, Decl(conditionalTypesSimplifyWhenTrivial.ts, 48, 14)) +>x : Symbol(x, Decl(conditionalTypesSimplifyWhenTrivial.ts, 48, 17)) + + x = y; +>x : Symbol(x, Decl(conditionalTypesSimplifyWhenTrivial.ts, 48, 17)) +>y : Symbol(y, Decl(conditionalTypesSimplifyWhenTrivial.ts, 49, 7)) +} + +const fn11 = ( +>fn11 : Symbol(fn11, Decl(conditionalTypesSimplifyWhenTrivial.ts, 53, 5)) +>Params : Symbol(Params, Decl(conditionalTypesSimplifyWhenTrivial.ts, 53, 14)) + + params: Pick>, +>params : Symbol(params, Decl(conditionalTypesSimplifyWhenTrivial.ts, 53, 22)) +>Pick : Symbol(Pick, Decl(lib.es5.d.ts, --, --)) +>Params : Symbol(Params, Decl(conditionalTypesSimplifyWhenTrivial.ts, 53, 14)) +>TemplatedConditional : Symbol(TemplatedConditional, Decl(conditionalTypesSimplifyWhenTrivial.ts, 40, 1)) +>Params : Symbol(Params, Decl(conditionalTypesSimplifyWhenTrivial.ts, 53, 14)) +>Params : Symbol(Params, Decl(conditionalTypesSimplifyWhenTrivial.ts, 53, 14)) +>Params : Symbol(Params, Decl(conditionalTypesSimplifyWhenTrivial.ts, 53, 14)) + +): Params => params; +>Params : Symbol(Params, Decl(conditionalTypesSimplifyWhenTrivial.ts, 53, 14)) +>params : Symbol(params, Decl(conditionalTypesSimplifyWhenTrivial.ts, 53, 22)) + +function fn12(x: TemplatedConditional) { +>fn12 : Symbol(fn12, Decl(conditionalTypesSimplifyWhenTrivial.ts, 55, 20)) +>T : Symbol(T, Decl(conditionalTypesSimplifyWhenTrivial.ts, 57, 14)) +>x : Symbol(x, Decl(conditionalTypesSimplifyWhenTrivial.ts, 57, 17)) +>TemplatedConditional : Symbol(TemplatedConditional, Decl(conditionalTypesSimplifyWhenTrivial.ts, 40, 1)) +>T : Symbol(T, Decl(conditionalTypesSimplifyWhenTrivial.ts, 57, 14)) +>T : Symbol(T, Decl(conditionalTypesSimplifyWhenTrivial.ts, 57, 14)) +>T : Symbol(T, Decl(conditionalTypesSimplifyWhenTrivial.ts, 57, 14)) + + var y: T = x; +>y : Symbol(y, Decl(conditionalTypesSimplifyWhenTrivial.ts, 58, 7)) +>T : Symbol(T, Decl(conditionalTypesSimplifyWhenTrivial.ts, 57, 14)) +>x : Symbol(x, Decl(conditionalTypesSimplifyWhenTrivial.ts, 57, 17)) + + x = y; +>x : Symbol(x, Decl(conditionalTypesSimplifyWhenTrivial.ts, 57, 17)) +>y : Symbol(y, Decl(conditionalTypesSimplifyWhenTrivial.ts, 58, 7)) +} + +declare var z: any; +>z : Symbol(z, Decl(conditionalTypesSimplifyWhenTrivial.ts, 62, 11)) + +const zee = z!!!; // since x is `any`, `x extends null | undefined` should be both true and false - and thus yield `any` +>zee : Symbol(zee, Decl(conditionalTypesSimplifyWhenTrivial.ts, 63, 5)) +>z : Symbol(z, Decl(conditionalTypesSimplifyWhenTrivial.ts, 62, 11)) + diff --git a/tests/baselines/reference/conditionalTypesSimplifyWhenTrivial.types b/tests/baselines/reference/conditionalTypesSimplifyWhenTrivial.types new file mode 100644 index 0000000000000..5f5131535605e --- /dev/null +++ b/tests/baselines/reference/conditionalTypesSimplifyWhenTrivial.types @@ -0,0 +1,167 @@ +=== tests/cases/compiler/conditionalTypesSimplifyWhenTrivial.ts === +const fn1 = ( +>fn1 : (params: Pick) => Params +>( params: Pick>,): Params => params : (params: Pick) => Params + + params: Pick>, +>params : Pick + +): Params => params; +>params : Pick + +function fn2(x: Exclude) { +>fn2 : (x: T) => void +>x : T + + var y: T = x; +>y : T +>x : T + + x = y; +>x = y : T +>x : T +>y : T +} + +const fn3 = ( +>fn3 : (params: Pick) => Params +>( params: Pick>,): Params => params : (params: Pick) => Params + + params: Pick>, +>params : Pick + +): Params => params; +>params : Pick + +function fn4(x: Extract) { +>fn4 : (x: T) => void +>x : T + + var y: T = x; +>y : T +>x : T + + x = y; +>x = y : T +>x : T +>y : T +} + +declare var x: Extract; // Should be `numebr | string` and not `any` +>x : string | number + +type ExtractWithDefault = T extends U ? T : D; +>ExtractWithDefault : ExtractWithDefault + +type ExcludeWithDefault = T extends U ? D : T; +>ExcludeWithDefault : ExcludeWithDefault + +const fn5 = ( +>fn5 : (params: Pick) => Params +>( params: Pick>,): Params => params : (params: Pick) => Params + + params: Pick>, +>params : Pick + +): Params => params; +>params : Pick + +function fn6(x: ExcludeWithDefault) { +>fn6 : (x: T) => void +>x : T + + var y: T = x; +>y : T +>x : T + + x = y; +>x = y : T +>x : T +>y : T +} + +const fn7 = ( +>fn7 : (params: Pick) => Params +>( params: Pick>,): Params => params : (params: Pick) => Params + + params: Pick>, +>params : Pick + +): Params => params; +>params : Pick + +function fn8(x: ExtractWithDefault) { +>fn8 : (x: T) => void +>x : T + + var y: T = x; +>y : T +>x : T + + x = y; +>x = y : T +>x : T +>y : T +} + +type TemplatedConditional = TCheck extends TExtends ? TTrue : TFalse; +>TemplatedConditional : TemplatedConditional + +const fn9 = ( +>fn9 : (params: Pick) => Params +>( params: Pick>,): Params => params : (params: Pick) => Params + + params: Pick>, +>params : Pick + +): Params => params; +>params : Pick + +function fn10(x: TemplatedConditional) { +>fn10 : (x: T) => void +>x : T + + var y: T = x; +>y : T +>x : T + + x = y; +>x = y : T +>x : T +>y : T +} + +const fn11 = ( +>fn11 : (params: Pick) => Params +>( params: Pick>,): Params => params : (params: Pick) => Params + + params: Pick>, +>params : Pick + +): Params => params; +>params : Pick + +function fn12(x: TemplatedConditional) { +>fn12 : (x: T) => void +>x : T + + var y: T = x; +>y : T +>x : T + + x = y; +>x = y : T +>x : T +>y : T +} + +declare var z: any; +>z : any + +const zee = z!!!; // since x is `any`, `x extends null | undefined` should be both true and false - and thus yield `any` +>zee : any +>z!!! : any +>z!! : any +>z! : any +>z : any + diff --git a/tests/baselines/reference/propTypeValidatorInference.js b/tests/baselines/reference/propTypeValidatorInference.js new file mode 100644 index 0000000000000..3a6fa04fbe183 --- /dev/null +++ b/tests/baselines/reference/propTypeValidatorInference.js @@ -0,0 +1,121 @@ +//// [tests/cases/compiler/propTypeValidatorInference.ts] //// + +//// [index.d.ts] +export const nominalTypeHack: unique symbol; + +export type IsOptional = undefined | null extends T ? true : undefined extends T ? true : null extends T ? true : false; + +export type RequiredKeys = { [K in keyof V]-?: Exclude extends Validator ? IsOptional extends true ? never : K : never }[keyof V]; +export type OptionalKeys = Exclude>; +export type InferPropsInner = { [K in keyof V]-?: InferType; }; + +export interface Validator { + (props: object, propName: string, componentName: string, location: string, propFullName: string): Error | null; + [nominalTypeHack]?: T; +} + +export interface Requireable extends Validator { + isRequired: Validator>; +} + +export type ValidationMap = { [K in keyof T]?: Validator }; + +export type InferType = V extends Validator ? T : any; +export type InferProps = + & InferPropsInner>> + & Partial>>>; + +export const any: Requireable; +export const array: Requireable; +export const bool: Requireable; +export const string: Requireable; +export const number: Requireable; +export function shape

>(type: P): Requireable>; +export function oneOfType>(types: T[]): Requireable>>; + + +//// [file.ts] +import * as PropTypes from "prop-types"; +interface Props { + any?: any; + array: string[]; + bool: boolean; + shape: { + foo: string; + bar?: boolean; + baz?: any + }; + oneOfType: string | boolean | { + foo?: string; + bar: number; + }; +} + +type PropTypesMap = PropTypes.ValidationMap; + +const innerProps = { + foo: PropTypes.string.isRequired, + bar: PropTypes.bool, + baz: PropTypes.any +}; + +const arrayOfTypes = [PropTypes.string, PropTypes.bool, PropTypes.shape({ + foo: PropTypes.string, + bar: PropTypes.number.isRequired +})]; + +// TS checking +const propTypes: PropTypesMap = { + any: PropTypes.any, + array: PropTypes.array.isRequired, + bool: PropTypes.bool.isRequired, + shape: PropTypes.shape(innerProps).isRequired, + oneOfType: PropTypes.oneOfType(arrayOfTypes).isRequired, +}; + +// JS checking +const propTypesWithoutAnnotation = { + any: PropTypes.any, + array: PropTypes.array.isRequired, + bool: PropTypes.bool.isRequired, + shape: PropTypes.shape(innerProps).isRequired, + oneOfType: PropTypes.oneOfType(arrayOfTypes).isRequired, +}; + +type ExtractedProps = PropTypes.InferProps; + +type ExtractedPropsWithoutAnnotation = PropTypes.InferProps; + +type ExtractPropsMatch = ExtractedProps extends ExtractedPropsWithoutAnnotation ? true : false; +const x: true = (null as any as ExtractPropsMatch); + +//// [file.js] +"use strict"; +exports.__esModule = true; +var PropTypes = require("prop-types"); +var innerProps = { + foo: PropTypes.string.isRequired, + bar: PropTypes.bool, + baz: PropTypes.any +}; +var arrayOfTypes = [PropTypes.string, PropTypes.bool, PropTypes.shape({ + foo: PropTypes.string, + bar: PropTypes.number.isRequired + })]; +// TS checking +var propTypes = { + any: PropTypes.any, + array: PropTypes.array.isRequired, + bool: PropTypes.bool.isRequired, + shape: PropTypes.shape(innerProps).isRequired, + oneOfType: PropTypes.oneOfType(arrayOfTypes).isRequired +}; +// JS checking +var propTypesWithoutAnnotation = { + any: PropTypes.any, + array: PropTypes.array.isRequired, + bool: PropTypes.bool.isRequired, + shape: PropTypes.shape(innerProps).isRequired, + oneOfType: PropTypes.oneOfType(arrayOfTypes).isRequired +}; +var x = null; diff --git a/tests/baselines/reference/propTypeValidatorInference.symbols b/tests/baselines/reference/propTypeValidatorInference.symbols new file mode 100644 index 0000000000000..32a4a3c1abf3b --- /dev/null +++ b/tests/baselines/reference/propTypeValidatorInference.symbols @@ -0,0 +1,366 @@ +=== tests/cases/compiler/node_modules/prop-types/index.d.ts === +export const nominalTypeHack: unique symbol; +>nominalTypeHack : Symbol(nominalTypeHack, Decl(index.d.ts, 0, 12)) + +export type IsOptional = undefined | null extends T ? true : undefined extends T ? true : null extends T ? true : false; +>IsOptional : Symbol(IsOptional, Decl(index.d.ts, 0, 44)) +>T : Symbol(T, Decl(index.d.ts, 2, 23)) +>T : Symbol(T, Decl(index.d.ts, 2, 23)) +>T : Symbol(T, Decl(index.d.ts, 2, 23)) +>T : Symbol(T, Decl(index.d.ts, 2, 23)) + +export type RequiredKeys = { [K in keyof V]-?: Exclude extends Validator ? IsOptional extends true ? never : K : never }[keyof V]; +>RequiredKeys : Symbol(RequiredKeys, Decl(index.d.ts, 2, 123)) +>V : Symbol(V, Decl(index.d.ts, 4, 25)) +>K : Symbol(K, Decl(index.d.ts, 4, 33)) +>V : Symbol(V, Decl(index.d.ts, 4, 25)) +>Exclude : Symbol(Exclude, Decl(lib.es5.d.ts, --, --)) +>V : Symbol(V, Decl(index.d.ts, 4, 25)) +>K : Symbol(K, Decl(index.d.ts, 4, 33)) +>Validator : Symbol(Validator, Decl(index.d.ts, 6, 72)) +>T : Symbol(T, Decl(index.d.ts, 4, 98)) +>IsOptional : Symbol(IsOptional, Decl(index.d.ts, 0, 44)) +>T : Symbol(T, Decl(index.d.ts, 4, 98)) +>K : Symbol(K, Decl(index.d.ts, 4, 33)) +>V : Symbol(V, Decl(index.d.ts, 4, 25)) + +export type OptionalKeys = Exclude>; +>OptionalKeys : Symbol(OptionalKeys, Decl(index.d.ts, 4, 162)) +>V : Symbol(V, Decl(index.d.ts, 5, 25)) +>Exclude : Symbol(Exclude, Decl(lib.es5.d.ts, --, --)) +>V : Symbol(V, Decl(index.d.ts, 5, 25)) +>RequiredKeys : Symbol(RequiredKeys, Decl(index.d.ts, 2, 123)) +>V : Symbol(V, Decl(index.d.ts, 5, 25)) + +export type InferPropsInner = { [K in keyof V]-?: InferType; }; +>InferPropsInner : Symbol(InferPropsInner, Decl(index.d.ts, 5, 64)) +>V : Symbol(V, Decl(index.d.ts, 6, 28)) +>K : Symbol(K, Decl(index.d.ts, 6, 36)) +>V : Symbol(V, Decl(index.d.ts, 6, 28)) +>InferType : Symbol(InferType, Decl(index.d.ts, 17, 68)) +>V : Symbol(V, Decl(index.d.ts, 6, 28)) +>K : Symbol(K, Decl(index.d.ts, 6, 36)) + +export interface Validator { +>Validator : Symbol(Validator, Decl(index.d.ts, 6, 72)) +>T : Symbol(T, Decl(index.d.ts, 8, 27)) + + (props: object, propName: string, componentName: string, location: string, propFullName: string): Error | null; +>props : Symbol(props, Decl(index.d.ts, 9, 5)) +>propName : Symbol(propName, Decl(index.d.ts, 9, 19)) +>componentName : Symbol(componentName, Decl(index.d.ts, 9, 37)) +>location : Symbol(location, Decl(index.d.ts, 9, 60)) +>propFullName : Symbol(propFullName, Decl(index.d.ts, 9, 78)) +>Error : Symbol(Error, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --)) + + [nominalTypeHack]?: T; +>[nominalTypeHack] : Symbol(Validator[nominalTypeHack], Decl(index.d.ts, 9, 115)) +>nominalTypeHack : Symbol(nominalTypeHack, Decl(index.d.ts, 0, 12)) +>T : Symbol(T, Decl(index.d.ts, 8, 27)) +} + +export interface Requireable extends Validator { +>Requireable : Symbol(Requireable, Decl(index.d.ts, 11, 1)) +>T : Symbol(T, Decl(index.d.ts, 13, 29)) +>Validator : Symbol(Validator, Decl(index.d.ts, 6, 72)) +>T : Symbol(T, Decl(index.d.ts, 13, 29)) + + isRequired: Validator>; +>isRequired : Symbol(Requireable.isRequired, Decl(index.d.ts, 13, 73)) +>Validator : Symbol(Validator, Decl(index.d.ts, 6, 72)) +>NonNullable : Symbol(NonNullable, Decl(lib.es5.d.ts, --, --)) +>T : Symbol(T, Decl(index.d.ts, 13, 29)) +} + +export type ValidationMap = { [K in keyof T]?: Validator }; +>ValidationMap : Symbol(ValidationMap, Decl(index.d.ts, 15, 1)) +>T : Symbol(T, Decl(index.d.ts, 17, 26)) +>K : Symbol(K, Decl(index.d.ts, 17, 34)) +>T : Symbol(T, Decl(index.d.ts, 17, 26)) +>Validator : Symbol(Validator, Decl(index.d.ts, 6, 72)) +>T : Symbol(T, Decl(index.d.ts, 17, 26)) +>K : Symbol(K, Decl(index.d.ts, 17, 34)) + +export type InferType = V extends Validator ? T : any; +>InferType : Symbol(InferType, Decl(index.d.ts, 17, 68)) +>V : Symbol(V, Decl(index.d.ts, 19, 22)) +>V : Symbol(V, Decl(index.d.ts, 19, 22)) +>Validator : Symbol(Validator, Decl(index.d.ts, 6, 72)) +>T : Symbol(T, Decl(index.d.ts, 19, 52)) +>T : Symbol(T, Decl(index.d.ts, 19, 52)) + +export type InferProps = +>InferProps : Symbol(InferProps, Decl(index.d.ts, 19, 66)) +>V : Symbol(V, Decl(index.d.ts, 20, 23)) + + & InferPropsInner>> +>InferPropsInner : Symbol(InferPropsInner, Decl(index.d.ts, 5, 64)) +>Pick : Symbol(Pick, Decl(lib.es5.d.ts, --, --)) +>V : Symbol(V, Decl(index.d.ts, 20, 23)) +>RequiredKeys : Symbol(RequiredKeys, Decl(index.d.ts, 2, 123)) +>V : Symbol(V, Decl(index.d.ts, 20, 23)) + + & Partial>>>; +>Partial : Symbol(Partial, Decl(lib.es5.d.ts, --, --)) +>InferPropsInner : Symbol(InferPropsInner, Decl(index.d.ts, 5, 64)) +>Pick : Symbol(Pick, Decl(lib.es5.d.ts, --, --)) +>V : Symbol(V, Decl(index.d.ts, 20, 23)) +>OptionalKeys : Symbol(OptionalKeys, Decl(index.d.ts, 4, 162)) +>V : Symbol(V, Decl(index.d.ts, 20, 23)) + +export const any: Requireable; +>any : Symbol(any, Decl(index.d.ts, 24, 12)) +>Requireable : Symbol(Requireable, Decl(index.d.ts, 11, 1)) + +export const array: Requireable; +>array : Symbol(array, Decl(index.d.ts, 25, 12)) +>Requireable : Symbol(Requireable, Decl(index.d.ts, 11, 1)) + +export const bool: Requireable; +>bool : Symbol(bool, Decl(index.d.ts, 26, 12)) +>Requireable : Symbol(Requireable, Decl(index.d.ts, 11, 1)) + +export const string: Requireable; +>string : Symbol(string, Decl(index.d.ts, 27, 12)) +>Requireable : Symbol(Requireable, Decl(index.d.ts, 11, 1)) + +export const number: Requireable; +>number : Symbol(number, Decl(index.d.ts, 28, 12)) +>Requireable : Symbol(Requireable, Decl(index.d.ts, 11, 1)) + +export function shape

>(type: P): Requireable>; +>shape : Symbol(shape, Decl(index.d.ts, 28, 41)) +>P : Symbol(P, Decl(index.d.ts, 29, 22)) +>ValidationMap : Symbol(ValidationMap, Decl(index.d.ts, 15, 1)) +>type : Symbol(type, Decl(index.d.ts, 29, 52)) +>P : Symbol(P, Decl(index.d.ts, 29, 22)) +>Requireable : Symbol(Requireable, Decl(index.d.ts, 11, 1)) +>InferProps : Symbol(InferProps, Decl(index.d.ts, 19, 66)) +>P : Symbol(P, Decl(index.d.ts, 29, 22)) + +export function oneOfType>(types: T[]): Requireable>>; +>oneOfType : Symbol(oneOfType, Decl(index.d.ts, 29, 89)) +>T : Symbol(T, Decl(index.d.ts, 30, 26)) +>Validator : Symbol(Validator, Decl(index.d.ts, 6, 72)) +>types : Symbol(types, Decl(index.d.ts, 30, 52)) +>T : Symbol(T, Decl(index.d.ts, 30, 26)) +>Requireable : Symbol(Requireable, Decl(index.d.ts, 11, 1)) +>NonNullable : Symbol(NonNullable, Decl(lib.es5.d.ts, --, --)) +>InferType : Symbol(InferType, Decl(index.d.ts, 17, 68)) +>T : Symbol(T, Decl(index.d.ts, 30, 26)) + + +=== tests/cases/compiler/file.ts === +import * as PropTypes from "prop-types"; +>PropTypes : Symbol(PropTypes, Decl(file.ts, 0, 6)) + +interface Props { +>Props : Symbol(Props, Decl(file.ts, 0, 40)) + + any?: any; +>any : Symbol(Props.any, Decl(file.ts, 1, 17)) + + array: string[]; +>array : Symbol(Props.array, Decl(file.ts, 2, 14)) + + bool: boolean; +>bool : Symbol(Props.bool, Decl(file.ts, 3, 20)) + + shape: { +>shape : Symbol(Props.shape, Decl(file.ts, 4, 18)) + + foo: string; +>foo : Symbol(foo, Decl(file.ts, 5, 12)) + + bar?: boolean; +>bar : Symbol(bar, Decl(file.ts, 6, 20)) + + baz?: any +>baz : Symbol(baz, Decl(file.ts, 7, 22)) + + }; + oneOfType: string | boolean | { +>oneOfType : Symbol(Props.oneOfType, Decl(file.ts, 9, 6)) + + foo?: string; +>foo : Symbol(foo, Decl(file.ts, 10, 35)) + + bar: number; +>bar : Symbol(bar, Decl(file.ts, 11, 21)) + + }; +} + +type PropTypesMap = PropTypes.ValidationMap; +>PropTypesMap : Symbol(PropTypesMap, Decl(file.ts, 14, 1)) +>PropTypes : Symbol(PropTypes, Decl(file.ts, 0, 6)) +>ValidationMap : Symbol(PropTypes.ValidationMap, Decl(index.d.ts, 15, 1)) +>Props : Symbol(Props, Decl(file.ts, 0, 40)) + +const innerProps = { +>innerProps : Symbol(innerProps, Decl(file.ts, 18, 5)) + + foo: PropTypes.string.isRequired, +>foo : Symbol(foo, Decl(file.ts, 18, 20)) +>PropTypes.string.isRequired : Symbol(PropTypes.Requireable.isRequired, Decl(index.d.ts, 13, 73)) +>PropTypes.string : Symbol(PropTypes.string, Decl(index.d.ts, 27, 12)) +>PropTypes : Symbol(PropTypes, Decl(file.ts, 0, 6)) +>string : Symbol(PropTypes.string, Decl(index.d.ts, 27, 12)) +>isRequired : Symbol(PropTypes.Requireable.isRequired, Decl(index.d.ts, 13, 73)) + + bar: PropTypes.bool, +>bar : Symbol(bar, Decl(file.ts, 19, 37)) +>PropTypes.bool : Symbol(PropTypes.bool, Decl(index.d.ts, 26, 12)) +>PropTypes : Symbol(PropTypes, Decl(file.ts, 0, 6)) +>bool : Symbol(PropTypes.bool, Decl(index.d.ts, 26, 12)) + + baz: PropTypes.any +>baz : Symbol(baz, Decl(file.ts, 20, 24)) +>PropTypes.any : Symbol(PropTypes.any, Decl(index.d.ts, 24, 12)) +>PropTypes : Symbol(PropTypes, Decl(file.ts, 0, 6)) +>any : Symbol(PropTypes.any, Decl(index.d.ts, 24, 12)) + +}; + +const arrayOfTypes = [PropTypes.string, PropTypes.bool, PropTypes.shape({ +>arrayOfTypes : Symbol(arrayOfTypes, Decl(file.ts, 24, 5)) +>PropTypes.string : Symbol(PropTypes.string, Decl(index.d.ts, 27, 12)) +>PropTypes : Symbol(PropTypes, Decl(file.ts, 0, 6)) +>string : Symbol(PropTypes.string, Decl(index.d.ts, 27, 12)) +>PropTypes.bool : Symbol(PropTypes.bool, Decl(index.d.ts, 26, 12)) +>PropTypes : Symbol(PropTypes, Decl(file.ts, 0, 6)) +>bool : Symbol(PropTypes.bool, Decl(index.d.ts, 26, 12)) +>PropTypes.shape : Symbol(PropTypes.shape, Decl(index.d.ts, 28, 41)) +>PropTypes : Symbol(PropTypes, Decl(file.ts, 0, 6)) +>shape : Symbol(PropTypes.shape, Decl(index.d.ts, 28, 41)) + + foo: PropTypes.string, +>foo : Symbol(foo, Decl(file.ts, 24, 73)) +>PropTypes.string : Symbol(PropTypes.string, Decl(index.d.ts, 27, 12)) +>PropTypes : Symbol(PropTypes, Decl(file.ts, 0, 6)) +>string : Symbol(PropTypes.string, Decl(index.d.ts, 27, 12)) + + bar: PropTypes.number.isRequired +>bar : Symbol(bar, Decl(file.ts, 25, 26)) +>PropTypes.number.isRequired : Symbol(PropTypes.Requireable.isRequired, Decl(index.d.ts, 13, 73)) +>PropTypes.number : Symbol(PropTypes.number, Decl(index.d.ts, 28, 12)) +>PropTypes : Symbol(PropTypes, Decl(file.ts, 0, 6)) +>number : Symbol(PropTypes.number, Decl(index.d.ts, 28, 12)) +>isRequired : Symbol(PropTypes.Requireable.isRequired, Decl(index.d.ts, 13, 73)) + +})]; + +// TS checking +const propTypes: PropTypesMap = { +>propTypes : Symbol(propTypes, Decl(file.ts, 30, 5)) +>PropTypesMap : Symbol(PropTypesMap, Decl(file.ts, 14, 1)) + + any: PropTypes.any, +>any : Symbol(any, Decl(file.ts, 30, 33)) +>PropTypes.any : Symbol(PropTypes.any, Decl(index.d.ts, 24, 12)) +>PropTypes : Symbol(PropTypes, Decl(file.ts, 0, 6)) +>any : Symbol(PropTypes.any, Decl(index.d.ts, 24, 12)) + + array: PropTypes.array.isRequired, +>array : Symbol(array, Decl(file.ts, 31, 23)) +>PropTypes.array.isRequired : Symbol(PropTypes.Requireable.isRequired, Decl(index.d.ts, 13, 73)) +>PropTypes.array : Symbol(PropTypes.array, Decl(index.d.ts, 25, 12)) +>PropTypes : Symbol(PropTypes, Decl(file.ts, 0, 6)) +>array : Symbol(PropTypes.array, Decl(index.d.ts, 25, 12)) +>isRequired : Symbol(PropTypes.Requireable.isRequired, Decl(index.d.ts, 13, 73)) + + bool: PropTypes.bool.isRequired, +>bool : Symbol(bool, Decl(file.ts, 32, 38)) +>PropTypes.bool.isRequired : Symbol(PropTypes.Requireable.isRequired, Decl(index.d.ts, 13, 73)) +>PropTypes.bool : Symbol(PropTypes.bool, Decl(index.d.ts, 26, 12)) +>PropTypes : Symbol(PropTypes, Decl(file.ts, 0, 6)) +>bool : Symbol(PropTypes.bool, Decl(index.d.ts, 26, 12)) +>isRequired : Symbol(PropTypes.Requireable.isRequired, Decl(index.d.ts, 13, 73)) + + shape: PropTypes.shape(innerProps).isRequired, +>shape : Symbol(shape, Decl(file.ts, 33, 36)) +>PropTypes.shape(innerProps).isRequired : Symbol(PropTypes.Requireable.isRequired, Decl(index.d.ts, 13, 73)) +>PropTypes.shape : Symbol(PropTypes.shape, Decl(index.d.ts, 28, 41)) +>PropTypes : Symbol(PropTypes, Decl(file.ts, 0, 6)) +>shape : Symbol(PropTypes.shape, Decl(index.d.ts, 28, 41)) +>innerProps : Symbol(innerProps, Decl(file.ts, 18, 5)) +>isRequired : Symbol(PropTypes.Requireable.isRequired, Decl(index.d.ts, 13, 73)) + + oneOfType: PropTypes.oneOfType(arrayOfTypes).isRequired, +>oneOfType : Symbol(oneOfType, Decl(file.ts, 34, 50)) +>PropTypes.oneOfType(arrayOfTypes).isRequired : Symbol(PropTypes.Requireable.isRequired, Decl(index.d.ts, 13, 73)) +>PropTypes.oneOfType : Symbol(PropTypes.oneOfType, Decl(index.d.ts, 29, 89)) +>PropTypes : Symbol(PropTypes, Decl(file.ts, 0, 6)) +>oneOfType : Symbol(PropTypes.oneOfType, Decl(index.d.ts, 29, 89)) +>arrayOfTypes : Symbol(arrayOfTypes, Decl(file.ts, 24, 5)) +>isRequired : Symbol(PropTypes.Requireable.isRequired, Decl(index.d.ts, 13, 73)) + +}; + +// JS checking +const propTypesWithoutAnnotation = { +>propTypesWithoutAnnotation : Symbol(propTypesWithoutAnnotation, Decl(file.ts, 39, 5)) + + any: PropTypes.any, +>any : Symbol(any, Decl(file.ts, 39, 36)) +>PropTypes.any : Symbol(PropTypes.any, Decl(index.d.ts, 24, 12)) +>PropTypes : Symbol(PropTypes, Decl(file.ts, 0, 6)) +>any : Symbol(PropTypes.any, Decl(index.d.ts, 24, 12)) + + array: PropTypes.array.isRequired, +>array : Symbol(array, Decl(file.ts, 40, 23)) +>PropTypes.array.isRequired : Symbol(PropTypes.Requireable.isRequired, Decl(index.d.ts, 13, 73)) +>PropTypes.array : Symbol(PropTypes.array, Decl(index.d.ts, 25, 12)) +>PropTypes : Symbol(PropTypes, Decl(file.ts, 0, 6)) +>array : Symbol(PropTypes.array, Decl(index.d.ts, 25, 12)) +>isRequired : Symbol(PropTypes.Requireable.isRequired, Decl(index.d.ts, 13, 73)) + + bool: PropTypes.bool.isRequired, +>bool : Symbol(bool, Decl(file.ts, 41, 38)) +>PropTypes.bool.isRequired : Symbol(PropTypes.Requireable.isRequired, Decl(index.d.ts, 13, 73)) +>PropTypes.bool : Symbol(PropTypes.bool, Decl(index.d.ts, 26, 12)) +>PropTypes : Symbol(PropTypes, Decl(file.ts, 0, 6)) +>bool : Symbol(PropTypes.bool, Decl(index.d.ts, 26, 12)) +>isRequired : Symbol(PropTypes.Requireable.isRequired, Decl(index.d.ts, 13, 73)) + + shape: PropTypes.shape(innerProps).isRequired, +>shape : Symbol(shape, Decl(file.ts, 42, 36)) +>PropTypes.shape(innerProps).isRequired : Symbol(PropTypes.Requireable.isRequired, Decl(index.d.ts, 13, 73)) +>PropTypes.shape : Symbol(PropTypes.shape, Decl(index.d.ts, 28, 41)) +>PropTypes : Symbol(PropTypes, Decl(file.ts, 0, 6)) +>shape : Symbol(PropTypes.shape, Decl(index.d.ts, 28, 41)) +>innerProps : Symbol(innerProps, Decl(file.ts, 18, 5)) +>isRequired : Symbol(PropTypes.Requireable.isRequired, Decl(index.d.ts, 13, 73)) + + oneOfType: PropTypes.oneOfType(arrayOfTypes).isRequired, +>oneOfType : Symbol(oneOfType, Decl(file.ts, 43, 50)) +>PropTypes.oneOfType(arrayOfTypes).isRequired : Symbol(PropTypes.Requireable.isRequired, Decl(index.d.ts, 13, 73)) +>PropTypes.oneOfType : Symbol(PropTypes.oneOfType, Decl(index.d.ts, 29, 89)) +>PropTypes : Symbol(PropTypes, Decl(file.ts, 0, 6)) +>oneOfType : Symbol(PropTypes.oneOfType, Decl(index.d.ts, 29, 89)) +>arrayOfTypes : Symbol(arrayOfTypes, Decl(file.ts, 24, 5)) +>isRequired : Symbol(PropTypes.Requireable.isRequired, Decl(index.d.ts, 13, 73)) + +}; + +type ExtractedProps = PropTypes.InferProps; +>ExtractedProps : Symbol(ExtractedProps, Decl(file.ts, 45, 2)) +>PropTypes : Symbol(PropTypes, Decl(file.ts, 0, 6)) +>InferProps : Symbol(PropTypes.InferProps, Decl(index.d.ts, 19, 66)) +>propTypes : Symbol(propTypes, Decl(file.ts, 30, 5)) + +type ExtractedPropsWithoutAnnotation = PropTypes.InferProps; +>ExtractedPropsWithoutAnnotation : Symbol(ExtractedPropsWithoutAnnotation, Decl(file.ts, 47, 61)) +>PropTypes : Symbol(PropTypes, Decl(file.ts, 0, 6)) +>InferProps : Symbol(PropTypes.InferProps, Decl(index.d.ts, 19, 66)) +>propTypesWithoutAnnotation : Symbol(propTypesWithoutAnnotation, Decl(file.ts, 39, 5)) + +type ExtractPropsMatch = ExtractedProps extends ExtractedPropsWithoutAnnotation ? true : false; +>ExtractPropsMatch : Symbol(ExtractPropsMatch, Decl(file.ts, 49, 95)) +>ExtractedProps : Symbol(ExtractedProps, Decl(file.ts, 45, 2)) +>ExtractedPropsWithoutAnnotation : Symbol(ExtractedPropsWithoutAnnotation, Decl(file.ts, 47, 61)) + +const x: true = (null as any as ExtractPropsMatch); +>x : Symbol(x, Decl(file.ts, 52, 5)) +>ExtractPropsMatch : Symbol(ExtractPropsMatch, Decl(file.ts, 49, 95)) + diff --git a/tests/baselines/reference/propTypeValidatorInference.types b/tests/baselines/reference/propTypeValidatorInference.types new file mode 100644 index 0000000000000..eb292dac5c486 --- /dev/null +++ b/tests/baselines/reference/propTypeValidatorInference.types @@ -0,0 +1,301 @@ +=== tests/cases/compiler/node_modules/prop-types/index.d.ts === +export const nominalTypeHack: unique symbol; +>nominalTypeHack : unique symbol + +export type IsOptional = undefined | null extends T ? true : undefined extends T ? true : null extends T ? true : false; +>IsOptional : IsOptional +>null : null +>true : true +>true : true +>null : null +>true : true +>false : false + +export type RequiredKeys = { [K in keyof V]-?: Exclude extends Validator ? IsOptional extends true ? never : K : never }[keyof V]; +>RequiredKeys : { [K in keyof V]-?: Exclude extends Validator ? IsOptional extends true ? never : K : never; }[keyof V] +>true : true + +export type OptionalKeys = Exclude>; +>OptionalKeys : Exclude extends Validator ? IsOptional extends true ? never : K : never; }[keyof V]> + +export type InferPropsInner = { [K in keyof V]-?: InferType; }; +>InferPropsInner : InferPropsInner + +export interface Validator { + (props: object, propName: string, componentName: string, location: string, propFullName: string): Error | null; +>props : object +>propName : string +>componentName : string +>location : string +>propFullName : string +>null : null + + [nominalTypeHack]?: T; +>[nominalTypeHack] : T | undefined +>nominalTypeHack : unique symbol +} + +export interface Requireable extends Validator { +>null : null + + isRequired: Validator>; +>isRequired : Validator> +} + +export type ValidationMap = { [K in keyof T]?: Validator }; +>ValidationMap : ValidationMap + +export type InferType = V extends Validator ? T : any; +>InferType : InferType + +export type InferProps = +>InferProps : InferProps + + & InferPropsInner>> + & Partial>>>; + +export const any: Requireable; +>any : Requireable + +export const array: Requireable; +>array : Requireable + +export const bool: Requireable; +>bool : Requireable + +export const string: Requireable; +>string : Requireable + +export const number: Requireable; +>number : Requireable + +export function shape

>(type: P): Requireable>; +>shape :

>(type: P) => Requireable> +>type : P + +export function oneOfType>(types: T[]): Requireable>>; +>oneOfType : >(types: T[]) => Requireable>> +>types : T[] + + +=== tests/cases/compiler/file.ts === +import * as PropTypes from "prop-types"; +>PropTypes : typeof PropTypes + +interface Props { + any?: any; +>any : any + + array: string[]; +>array : string[] + + bool: boolean; +>bool : boolean + + shape: { +>shape : { foo: string; bar?: boolean | undefined; baz?: any; } + + foo: string; +>foo : string + + bar?: boolean; +>bar : boolean | undefined + + baz?: any +>baz : any + + }; + oneOfType: string | boolean | { +>oneOfType : string | boolean | { foo?: string | undefined; bar: number; } + + foo?: string; +>foo : string | undefined + + bar: number; +>bar : number + + }; +} + +type PropTypesMap = PropTypes.ValidationMap; +>PropTypesMap : PropTypes.ValidationMap +>PropTypes : any + +const innerProps = { +>innerProps : { foo: PropTypes.Validator; bar: PropTypes.Requireable; baz: PropTypes.Requireable; } +>{ foo: PropTypes.string.isRequired, bar: PropTypes.bool, baz: PropTypes.any} : { foo: PropTypes.Validator; bar: PropTypes.Requireable; baz: PropTypes.Requireable; } + + foo: PropTypes.string.isRequired, +>foo : PropTypes.Validator +>PropTypes.string.isRequired : PropTypes.Validator +>PropTypes.string : PropTypes.Requireable +>PropTypes : typeof PropTypes +>string : PropTypes.Requireable +>isRequired : PropTypes.Validator + + bar: PropTypes.bool, +>bar : PropTypes.Requireable +>PropTypes.bool : PropTypes.Requireable +>PropTypes : typeof PropTypes +>bool : PropTypes.Requireable + + baz: PropTypes.any +>baz : PropTypes.Requireable +>PropTypes.any : PropTypes.Requireable +>PropTypes : typeof PropTypes +>any : PropTypes.Requireable + +}; + +const arrayOfTypes = [PropTypes.string, PropTypes.bool, PropTypes.shape({ +>arrayOfTypes : (PropTypes.Requireable | PropTypes.Requireable | PropTypes.Requireable; bar: PropTypes.Validator; }>>)[] +>[PropTypes.string, PropTypes.bool, PropTypes.shape({ foo: PropTypes.string, bar: PropTypes.number.isRequired})] : (PropTypes.Requireable | PropTypes.Requireable | PropTypes.Requireable; bar: PropTypes.Validator; }>>)[] +>PropTypes.string : PropTypes.Requireable +>PropTypes : typeof PropTypes +>string : PropTypes.Requireable +>PropTypes.bool : PropTypes.Requireable +>PropTypes : typeof PropTypes +>bool : PropTypes.Requireable +>PropTypes.shape({ foo: PropTypes.string, bar: PropTypes.number.isRequired}) : PropTypes.Requireable; bar: PropTypes.Validator; }>> +>PropTypes.shape :

>(type: P) => PropTypes.Requireable> +>PropTypes : typeof PropTypes +>shape :

>(type: P) => PropTypes.Requireable> +>{ foo: PropTypes.string, bar: PropTypes.number.isRequired} : { foo: PropTypes.Requireable; bar: PropTypes.Validator; } + + foo: PropTypes.string, +>foo : PropTypes.Requireable +>PropTypes.string : PropTypes.Requireable +>PropTypes : typeof PropTypes +>string : PropTypes.Requireable + + bar: PropTypes.number.isRequired +>bar : PropTypes.Validator +>PropTypes.number.isRequired : PropTypes.Validator +>PropTypes.number : PropTypes.Requireable +>PropTypes : typeof PropTypes +>number : PropTypes.Requireable +>isRequired : PropTypes.Validator + +})]; + +// TS checking +const propTypes: PropTypesMap = { +>propTypes : PropTypes.ValidationMap +>{ any: PropTypes.any, array: PropTypes.array.isRequired, bool: PropTypes.bool.isRequired, shape: PropTypes.shape(innerProps).isRequired, oneOfType: PropTypes.oneOfType(arrayOfTypes).isRequired,} : { any: PropTypes.Requireable; array: PropTypes.Validator; bool: PropTypes.Validator; shape: PropTypes.Validator; bar: PropTypes.Requireable; baz: PropTypes.Requireable; }>>; oneOfType: PropTypes.Validator; bar: PropTypes.Validator; }>>; } + + any: PropTypes.any, +>any : PropTypes.Requireable +>PropTypes.any : PropTypes.Requireable +>PropTypes : typeof PropTypes +>any : PropTypes.Requireable + + array: PropTypes.array.isRequired, +>array : PropTypes.Validator +>PropTypes.array.isRequired : PropTypes.Validator +>PropTypes.array : PropTypes.Requireable +>PropTypes : typeof PropTypes +>array : PropTypes.Requireable +>isRequired : PropTypes.Validator + + bool: PropTypes.bool.isRequired, +>bool : PropTypes.Validator +>PropTypes.bool.isRequired : PropTypes.Validator +>PropTypes.bool : PropTypes.Requireable +>PropTypes : typeof PropTypes +>bool : PropTypes.Requireable +>isRequired : PropTypes.Validator + + shape: PropTypes.shape(innerProps).isRequired, +>shape : PropTypes.Validator; bar: PropTypes.Requireable; baz: PropTypes.Requireable; }>> +>PropTypes.shape(innerProps).isRequired : PropTypes.Validator; bar: PropTypes.Requireable; baz: PropTypes.Requireable; }>> +>PropTypes.shape(innerProps) : PropTypes.Requireable; bar: PropTypes.Requireable; baz: PropTypes.Requireable; }>> +>PropTypes.shape :

>(type: P) => PropTypes.Requireable> +>PropTypes : typeof PropTypes +>shape :

>(type: P) => PropTypes.Requireable> +>innerProps : { foo: PropTypes.Validator; bar: PropTypes.Requireable; baz: PropTypes.Requireable; } +>isRequired : PropTypes.Validator; bar: PropTypes.Requireable; baz: PropTypes.Requireable; }>> + + oneOfType: PropTypes.oneOfType(arrayOfTypes).isRequired, +>oneOfType : PropTypes.Validator; bar: PropTypes.Validator; }>> +>PropTypes.oneOfType(arrayOfTypes).isRequired : PropTypes.Validator; bar: PropTypes.Validator; }>> +>PropTypes.oneOfType(arrayOfTypes) : PropTypes.Requireable; bar: PropTypes.Validator; }>> +>PropTypes.oneOfType : >(types: T[]) => PropTypes.Requireable>> +>PropTypes : typeof PropTypes +>oneOfType : >(types: T[]) => PropTypes.Requireable>> +>arrayOfTypes : (PropTypes.Requireable | PropTypes.Requireable | PropTypes.Requireable; bar: PropTypes.Validator; }>>)[] +>isRequired : PropTypes.Validator; bar: PropTypes.Validator; }>> + +}; + +// JS checking +const propTypesWithoutAnnotation = { +>propTypesWithoutAnnotation : { any: PropTypes.Requireable; array: PropTypes.Validator; bool: PropTypes.Validator; shape: PropTypes.Validator; bar: PropTypes.Requireable; baz: PropTypes.Requireable; }>>; oneOfType: PropTypes.Validator; bar: PropTypes.Validator; }>>; } +>{ any: PropTypes.any, array: PropTypes.array.isRequired, bool: PropTypes.bool.isRequired, shape: PropTypes.shape(innerProps).isRequired, oneOfType: PropTypes.oneOfType(arrayOfTypes).isRequired,} : { any: PropTypes.Requireable; array: PropTypes.Validator; bool: PropTypes.Validator; shape: PropTypes.Validator; bar: PropTypes.Requireable; baz: PropTypes.Requireable; }>>; oneOfType: PropTypes.Validator; bar: PropTypes.Validator; }>>; } + + any: PropTypes.any, +>any : PropTypes.Requireable +>PropTypes.any : PropTypes.Requireable +>PropTypes : typeof PropTypes +>any : PropTypes.Requireable + + array: PropTypes.array.isRequired, +>array : PropTypes.Validator +>PropTypes.array.isRequired : PropTypes.Validator +>PropTypes.array : PropTypes.Requireable +>PropTypes : typeof PropTypes +>array : PropTypes.Requireable +>isRequired : PropTypes.Validator + + bool: PropTypes.bool.isRequired, +>bool : PropTypes.Validator +>PropTypes.bool.isRequired : PropTypes.Validator +>PropTypes.bool : PropTypes.Requireable +>PropTypes : typeof PropTypes +>bool : PropTypes.Requireable +>isRequired : PropTypes.Validator + + shape: PropTypes.shape(innerProps).isRequired, +>shape : PropTypes.Validator; bar: PropTypes.Requireable; baz: PropTypes.Requireable; }>> +>PropTypes.shape(innerProps).isRequired : PropTypes.Validator; bar: PropTypes.Requireable; baz: PropTypes.Requireable; }>> +>PropTypes.shape(innerProps) : PropTypes.Requireable; bar: PropTypes.Requireable; baz: PropTypes.Requireable; }>> +>PropTypes.shape :

>(type: P) => PropTypes.Requireable> +>PropTypes : typeof PropTypes +>shape :

>(type: P) => PropTypes.Requireable> +>innerProps : { foo: PropTypes.Validator; bar: PropTypes.Requireable; baz: PropTypes.Requireable; } +>isRequired : PropTypes.Validator; bar: PropTypes.Requireable; baz: PropTypes.Requireable; }>> + + oneOfType: PropTypes.oneOfType(arrayOfTypes).isRequired, +>oneOfType : PropTypes.Validator; bar: PropTypes.Validator; }>> +>PropTypes.oneOfType(arrayOfTypes).isRequired : PropTypes.Validator; bar: PropTypes.Validator; }>> +>PropTypes.oneOfType(arrayOfTypes) : PropTypes.Requireable; bar: PropTypes.Validator; }>> +>PropTypes.oneOfType : >(types: T[]) => PropTypes.Requireable>> +>PropTypes : typeof PropTypes +>oneOfType : >(types: T[]) => PropTypes.Requireable>> +>arrayOfTypes : (PropTypes.Requireable | PropTypes.Requireable | PropTypes.Requireable; bar: PropTypes.Validator; }>>)[] +>isRequired : PropTypes.Validator; bar: PropTypes.Validator; }>> + +}; + +type ExtractedProps = PropTypes.InferProps; +>ExtractedProps : PropTypes.InferProps> +>PropTypes : any +>propTypes : PropTypes.ValidationMap + +type ExtractedPropsWithoutAnnotation = PropTypes.InferProps; +>ExtractedPropsWithoutAnnotation : PropTypes.InferProps<{ any: PropTypes.Requireable; array: PropTypes.Validator; bool: PropTypes.Validator; shape: PropTypes.Validator; bar: PropTypes.Requireable; baz: PropTypes.Requireable; }>>; oneOfType: PropTypes.Validator; bar: PropTypes.Validator; }>>; }> +>PropTypes : any +>propTypesWithoutAnnotation : { any: PropTypes.Requireable; array: PropTypes.Validator; bool: PropTypes.Validator; shape: PropTypes.Validator; bar: PropTypes.Requireable; baz: PropTypes.Requireable; }>>; oneOfType: PropTypes.Validator; bar: PropTypes.Validator; }>>; } + +type ExtractPropsMatch = ExtractedProps extends ExtractedPropsWithoutAnnotation ? true : false; +>ExtractPropsMatch : true +>true : true +>false : false + +const x: true = (null as any as ExtractPropsMatch); +>x : true +>true : true +>(null as any as ExtractPropsMatch) : true +>null as any as ExtractPropsMatch : true +>null as any : any +>null : null + diff --git a/tests/cases/compiler/conditionalTypesSimplifyWhenTrivial.ts b/tests/cases/compiler/conditionalTypesSimplifyWhenTrivial.ts new file mode 100644 index 0000000000000..de05b820de33b --- /dev/null +++ b/tests/cases/compiler/conditionalTypesSimplifyWhenTrivial.ts @@ -0,0 +1,65 @@ +// @strict: true +const fn1 = ( + params: Pick>, +): Params => params; + +function fn2(x: Exclude) { + var y: T = x; + x = y; +} + +const fn3 = ( + params: Pick>, +): Params => params; + +function fn4(x: Extract) { + var y: T = x; + x = y; +} + +declare var x: Extract; // Should be `numebr | string` and not `any` + +type ExtractWithDefault = T extends U ? T : D; + +type ExcludeWithDefault = T extends U ? D : T; + +const fn5 = ( + params: Pick>, +): Params => params; + +function fn6(x: ExcludeWithDefault) { + var y: T = x; + x = y; +} + +const fn7 = ( + params: Pick>, +): Params => params; + +function fn8(x: ExtractWithDefault) { + var y: T = x; + x = y; +} + +type TemplatedConditional = TCheck extends TExtends ? TTrue : TFalse; + +const fn9 = ( + params: Pick>, +): Params => params; + +function fn10(x: TemplatedConditional) { + var y: T = x; + x = y; +} + +const fn11 = ( + params: Pick>, +): Params => params; + +function fn12(x: TemplatedConditional) { + var y: T = x; + x = y; +} + +declare var z: any; +const zee = z!!!; // since x is `any`, `x extends null | undefined` should be both true and false - and thus yield `any` diff --git a/tests/cases/compiler/propTypeValidatorInference.ts b/tests/cases/compiler/propTypeValidatorInference.ts new file mode 100644 index 0000000000000..54030ab91a916 --- /dev/null +++ b/tests/cases/compiler/propTypeValidatorInference.ts @@ -0,0 +1,89 @@ +// @strict: true +// @filename: node_modules/prop-types/index.d.ts +export const nominalTypeHack: unique symbol; + +export type IsOptional = undefined | null extends T ? true : undefined extends T ? true : null extends T ? true : false; + +export type RequiredKeys = { [K in keyof V]-?: Exclude extends Validator ? IsOptional extends true ? never : K : never }[keyof V]; +export type OptionalKeys = Exclude>; +export type InferPropsInner = { [K in keyof V]-?: InferType; }; + +export interface Validator { + (props: object, propName: string, componentName: string, location: string, propFullName: string): Error | null; + [nominalTypeHack]?: T; +} + +export interface Requireable extends Validator { + isRequired: Validator>; +} + +export type ValidationMap = { [K in keyof T]?: Validator }; + +export type InferType = V extends Validator ? T : any; +export type InferProps = + & InferPropsInner>> + & Partial>>>; + +export const any: Requireable; +export const array: Requireable; +export const bool: Requireable; +export const string: Requireable; +export const number: Requireable; +export function shape

>(type: P): Requireable>; +export function oneOfType>(types: T[]): Requireable>>; + + +// @filename: file.ts +import * as PropTypes from "prop-types"; +interface Props { + any?: any; + array: string[]; + bool: boolean; + shape: { + foo: string; + bar?: boolean; + baz?: any + }; + oneOfType: string | boolean | { + foo?: string; + bar: number; + }; +} + +type PropTypesMap = PropTypes.ValidationMap; + +const innerProps = { + foo: PropTypes.string.isRequired, + bar: PropTypes.bool, + baz: PropTypes.any +}; + +const arrayOfTypes = [PropTypes.string, PropTypes.bool, PropTypes.shape({ + foo: PropTypes.string, + bar: PropTypes.number.isRequired +})]; + +// TS checking +const propTypes: PropTypesMap = { + any: PropTypes.any, + array: PropTypes.array.isRequired, + bool: PropTypes.bool.isRequired, + shape: PropTypes.shape(innerProps).isRequired, + oneOfType: PropTypes.oneOfType(arrayOfTypes).isRequired, +}; + +// JS checking +const propTypesWithoutAnnotation = { + any: PropTypes.any, + array: PropTypes.array.isRequired, + bool: PropTypes.bool.isRequired, + shape: PropTypes.shape(innerProps).isRequired, + oneOfType: PropTypes.oneOfType(arrayOfTypes).isRequired, +}; + +type ExtractedProps = PropTypes.InferProps; + +type ExtractedPropsWithoutAnnotation = PropTypes.InferProps; + +type ExtractPropsMatch = ExtractedProps extends ExtractedPropsWithoutAnnotation ? true : false; +const x: true = (null as any as ExtractPropsMatch); \ No newline at end of file