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
This commit is contained in:
Wesley Wigham 2019-03-08 15:33:12 -08:00 committed by GitHub
parent 6607e00b8f
commit a9ad94ab3c
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
12 changed files with 1554 additions and 27 deletions

View file

@ -387,6 +387,7 @@ namespace ts {
const intersectionTypes = createMap<IntersectionType>();
const literalTypes = createMap<LiteralType>();
const indexedAccessTypes = createMap<IndexedAccessType>();
const conditionalTypes = createMap<Type>();
const evolvingArrayTypes: EvolvingArrayType[] = [];
const undefinedProperties = createMap<Symbol>() as UnderscoreEscapedMap<Symbol>;
@ -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(((<SubstitutionType>rootTrueType).substitute), combinedMapper || mapper).flags & TypeFlags.AnyOrUnknown
? (<SubstitutionType>rootTrueType).typeVariable
: getIntersectionType([(<SubstitutionType>rootTrueType).substitute, (<SubstitutionType>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
: ((<SubstitutionType>rootTrueType).substitute).flags & TypeFlags.AnyOrUnknown
? (<SubstitutionType>rootTrueType).typeVariable
: getIntersectionType([(<SubstitutionType>rootTrueType).substitute, (<SubstitutionType>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 ? (<SubstitutionType>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 {

View file

@ -509,6 +509,8 @@ declare function f5<T extends Options, K extends string>(p: K): Extract<T, {
}>;
declare let x0: {
k: "a";
} & {
k: "a";
a: number;
};
declare type OptionsOfKind<K extends Options["k"]> = Extract<Options, {
@ -645,7 +647,7 @@ declare type T82 = Eq2<false, true>;
declare type T83 = Eq2<false, false>;
declare type Foo<T> = T extends string ? boolean : number;
declare type Bar<T> = T extends string ? boolean : number;
declare const convert: <U>(value: Foo<U>) => Bar<U>;
declare const convert: <U>(value: Foo<U>) => Foo<U>;
declare type Baz<T> = Foo<T>;
declare const convert2: <T>(value: Foo<T>) => Foo<T>;
declare function f31<T>(): void;

View file

@ -9,7 +9,7 @@ type T02 = Exclude<string | number | (() => void), Function>; // string | numbe
>T02 : string | number
type T03 = Extract<string | number | (() => void), Function>; // () => void
>T03 : () => void
>T03 : Function & (() => void)
type T04 = NonNullable<string | number | undefined>; // string | number
>T04 : string | number
@ -113,7 +113,7 @@ type T10 = Exclude<Options, { k: "a" | "b" }>; // { k: "c", c: boolean }
>k : "a" | "b"
type T11 = Extract<Options, { k: "a" | "b" }>; // { 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<Options, { k: "a" } | { k: "b" }>; // { k: "c", c: boolean }
@ -122,7 +122,7 @@ type T12 = Exclude<Options, { k: "a" } | { k: "b" }>; // { k: "c", c: boolean }
>k : "b"
type T13 = Extract<Options, { k: "a" } | { k: "b" }>; // { 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<T extends Options, K extends string>(p: K): Extract<T, { k:
>k : 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 : <T extends Options, K extends string>(p: K) => Extract<T, { k: K; }>
>"a" : "a"
@ -150,13 +150,13 @@ type OptionsOfKind<K extends Options["k"]> = Extract<Options, { k: K }>;
>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<T, K extends keyof T, V extends T[K]> = Extract<T, { [P in K]: V }>;
>Select : Extract<T, { [P in K]: V; }>
type T17 = Select<Options, "k", "a" | "b">; // // { 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<T> =
>TypeName : TypeName<T>
@ -779,8 +779,8 @@ type Bar<T> = T extends string ? boolean : number;
>Bar : Bar<T>
const convert = <U>(value: Foo<U>): Bar<U> => value;
>convert : <U>(value: Foo<U>) => Bar<U>
><U>(value: Foo<U>): Bar<U> => value : <U>(value: Foo<U>) => Bar<U>
>convert : <U>(value: Foo<U>) => Foo<U>
><U>(value: Foo<U>): Bar<U> => value : <U>(value: Foo<U>) => Foo<U>
>value : Foo<U>
>value : Foo<U>
@ -832,7 +832,7 @@ function f33<T, U>() {
>T1 : Foo<T & U>
type T2 = Bar<T & U>;
>T2 : Bar<T & U>
>T2 : Foo<T & U>
var z: T1;
>z : Foo<T & U>

View file

@ -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 : <T>(item: T) => Extract<T, Function>
>x : string | (() => string) | undefined
f();
>f() : string
>f : () => string
>f : Function & (() => string)
}
type Foo = { foo: string };

View file

@ -0,0 +1,100 @@
//// [conditionalTypesSimplifyWhenTrivial.ts]
const fn1 = <Params>(
params: Pick<Params, Exclude<keyof Params, never>>,
): Params => params;
function fn2<T>(x: Exclude<T, never>) {
var y: T = x;
x = y;
}
const fn3 = <Params>(
params: Pick<Params, Extract<keyof Params, keyof Params>>,
): Params => params;
function fn4<T>(x: Extract<T, T>) {
var y: T = x;
x = y;
}
declare var x: Extract<number | string, any>; // Should be `numebr | string` and not `any`
type ExtractWithDefault<T, U, D = never> = T extends U ? T : D;
type ExcludeWithDefault<T, U, D = never> = T extends U ? D : T;
const fn5 = <Params>(
params: Pick<Params, ExcludeWithDefault<keyof Params, never>>,
): Params => params;
function fn6<T>(x: ExcludeWithDefault<T, never>) {
var y: T = x;
x = y;
}
const fn7 = <Params>(
params: Pick<Params, ExtractWithDefault<keyof Params, keyof Params>>,
): Params => params;
function fn8<T>(x: ExtractWithDefault<T, T>) {
var y: T = x;
x = y;
}
type TemplatedConditional<TCheck, TExtends, TTrue, TFalse> = TCheck extends TExtends ? TTrue : TFalse;
const fn9 = <Params>(
params: Pick<Params, TemplatedConditional<keyof Params, never, never, keyof Params>>,
): Params => params;
function fn10<T>(x: TemplatedConditional<T, never, never, T>) {
var y: T = x;
x = y;
}
const fn11 = <Params>(
params: Pick<Params, TemplatedConditional<keyof Params, keyof Params, keyof Params, never>>,
): Params => params;
function fn12<T>(x: TemplatedConditional<T, T, T, never>) {
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`

View file

@ -0,0 +1,245 @@
=== tests/cases/compiler/conditionalTypesSimplifyWhenTrivial.ts ===
const fn1 = <Params>(
>fn1 : Symbol(fn1, Decl(conditionalTypesSimplifyWhenTrivial.ts, 0, 5))
>Params : Symbol(Params, Decl(conditionalTypesSimplifyWhenTrivial.ts, 0, 13))
params: Pick<Params, Exclude<keyof Params, never>>,
>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<T>(x: Exclude<T, never>) {
>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 = <Params>(
>fn3 : Symbol(fn3, Decl(conditionalTypesSimplifyWhenTrivial.ts, 9, 5))
>Params : Symbol(Params, Decl(conditionalTypesSimplifyWhenTrivial.ts, 9, 13))
params: Pick<Params, Extract<keyof Params, keyof Params>>,
>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<T>(x: Extract<T, T>) {
>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<number | string, any>; // 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, U, D = never> = 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, U, D = never> = 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 = <Params>(
>fn5 : Symbol(fn5, Decl(conditionalTypesSimplifyWhenTrivial.ts, 24, 5))
>Params : Symbol(Params, Decl(conditionalTypesSimplifyWhenTrivial.ts, 24, 13))
params: Pick<Params, ExcludeWithDefault<keyof Params, never>>,
>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<T>(x: ExcludeWithDefault<T, never>) {
>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 = <Params>(
>fn7 : Symbol(fn7, Decl(conditionalTypesSimplifyWhenTrivial.ts, 33, 5))
>Params : Symbol(Params, Decl(conditionalTypesSimplifyWhenTrivial.ts, 33, 13))
params: Pick<Params, ExtractWithDefault<keyof Params, keyof Params>>,
>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<T>(x: ExtractWithDefault<T, T>) {
>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, TExtends, TTrue, TFalse> = 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 = <Params>(
>fn9 : Symbol(fn9, Decl(conditionalTypesSimplifyWhenTrivial.ts, 44, 5))
>Params : Symbol(Params, Decl(conditionalTypesSimplifyWhenTrivial.ts, 44, 13))
params: Pick<Params, TemplatedConditional<keyof Params, never, never, keyof Params>>,
>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<T>(x: TemplatedConditional<T, never, never, T>) {
>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 = <Params>(
>fn11 : Symbol(fn11, Decl(conditionalTypesSimplifyWhenTrivial.ts, 53, 5))
>Params : Symbol(Params, Decl(conditionalTypesSimplifyWhenTrivial.ts, 53, 14))
params: Pick<Params, TemplatedConditional<keyof Params, keyof Params, keyof Params, never>>,
>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<T>(x: TemplatedConditional<T, T, T, never>) {
>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))

View file

@ -0,0 +1,167 @@
=== tests/cases/compiler/conditionalTypesSimplifyWhenTrivial.ts ===
const fn1 = <Params>(
>fn1 : <Params>(params: Pick<Params, keyof Params>) => Params
><Params>( params: Pick<Params, Exclude<keyof Params, never>>,): Params => params : <Params>(params: Pick<Params, keyof Params>) => Params
params: Pick<Params, Exclude<keyof Params, never>>,
>params : Pick<Params, keyof Params>
): Params => params;
>params : Pick<Params, keyof Params>
function fn2<T>(x: Exclude<T, never>) {
>fn2 : <T>(x: T) => void
>x : T
var y: T = x;
>y : T
>x : T
x = y;
>x = y : T
>x : T
>y : T
}
const fn3 = <Params>(
>fn3 : <Params>(params: Pick<Params, keyof Params>) => Params
><Params>( params: Pick<Params, Extract<keyof Params, keyof Params>>,): Params => params : <Params>(params: Pick<Params, keyof Params>) => Params
params: Pick<Params, Extract<keyof Params, keyof Params>>,
>params : Pick<Params, keyof Params>
): Params => params;
>params : Pick<Params, keyof Params>
function fn4<T>(x: Extract<T, T>) {
>fn4 : <T>(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<number | string, any>; // Should be `numebr | string` and not `any`
>x : string | number
type ExtractWithDefault<T, U, D = never> = T extends U ? T : D;
>ExtractWithDefault : ExtractWithDefault<T, U, D>
type ExcludeWithDefault<T, U, D = never> = T extends U ? D : T;
>ExcludeWithDefault : ExcludeWithDefault<T, U, D>
const fn5 = <Params>(
>fn5 : <Params>(params: Pick<Params, keyof Params>) => Params
><Params>( params: Pick<Params, ExcludeWithDefault<keyof Params, never>>,): Params => params : <Params>(params: Pick<Params, keyof Params>) => Params
params: Pick<Params, ExcludeWithDefault<keyof Params, never>>,
>params : Pick<Params, keyof Params>
): Params => params;
>params : Pick<Params, keyof Params>
function fn6<T>(x: ExcludeWithDefault<T, never>) {
>fn6 : <T>(x: T) => void
>x : T
var y: T = x;
>y : T
>x : T
x = y;
>x = y : T
>x : T
>y : T
}
const fn7 = <Params>(
>fn7 : <Params>(params: Pick<Params, keyof Params>) => Params
><Params>( params: Pick<Params, ExtractWithDefault<keyof Params, keyof Params>>,): Params => params : <Params>(params: Pick<Params, keyof Params>) => Params
params: Pick<Params, ExtractWithDefault<keyof Params, keyof Params>>,
>params : Pick<Params, keyof Params>
): Params => params;
>params : Pick<Params, keyof Params>
function fn8<T>(x: ExtractWithDefault<T, T>) {
>fn8 : <T>(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, TExtends, TTrue, TFalse> = TCheck extends TExtends ? TTrue : TFalse;
>TemplatedConditional : TemplatedConditional<TCheck, TExtends, TTrue, TFalse>
const fn9 = <Params>(
>fn9 : <Params>(params: Pick<Params, keyof Params>) => Params
><Params>( params: Pick<Params, TemplatedConditional<keyof Params, never, never, keyof Params>>,): Params => params : <Params>(params: Pick<Params, keyof Params>) => Params
params: Pick<Params, TemplatedConditional<keyof Params, never, never, keyof Params>>,
>params : Pick<Params, keyof Params>
): Params => params;
>params : Pick<Params, keyof Params>
function fn10<T>(x: TemplatedConditional<T, never, never, T>) {
>fn10 : <T>(x: T) => void
>x : T
var y: T = x;
>y : T
>x : T
x = y;
>x = y : T
>x : T
>y : T
}
const fn11 = <Params>(
>fn11 : <Params>(params: Pick<Params, keyof Params>) => Params
><Params>( params: Pick<Params, TemplatedConditional<keyof Params, keyof Params, keyof Params, never>>,): Params => params : <Params>(params: Pick<Params, keyof Params>) => Params
params: Pick<Params, TemplatedConditional<keyof Params, keyof Params, keyof Params, never>>,
>params : Pick<Params, keyof Params>
): Params => params;
>params : Pick<Params, keyof Params>
function fn12<T>(x: TemplatedConditional<T, T, T, never>) {
>fn12 : <T>(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

View file

@ -0,0 +1,121 @@
//// [tests/cases/compiler/propTypeValidatorInference.ts] ////
//// [index.d.ts]
export const nominalTypeHack: unique symbol;
export type IsOptional<T> = undefined | null extends T ? true : undefined extends T ? true : null extends T ? true : false;
export type RequiredKeys<V> = { [K in keyof V]-?: Exclude<V[K], undefined> extends Validator<infer T> ? IsOptional<T> extends true ? never : K : never }[keyof V];
export type OptionalKeys<V> = Exclude<keyof V, RequiredKeys<V>>;
export type InferPropsInner<V> = { [K in keyof V]-?: InferType<V[K]>; };
export interface Validator<T> {
(props: object, propName: string, componentName: string, location: string, propFullName: string): Error | null;
[nominalTypeHack]?: T;
}
export interface Requireable<T> extends Validator<T | undefined | null> {
isRequired: Validator<NonNullable<T>>;
}
export type ValidationMap<T> = { [K in keyof T]?: Validator<T[K]> };
export type InferType<V> = V extends Validator<infer T> ? T : any;
export type InferProps<V> =
& InferPropsInner<Pick<V, RequiredKeys<V>>>
& Partial<InferPropsInner<Pick<V, OptionalKeys<V>>>>;
export const any: Requireable<any>;
export const array: Requireable<any[]>;
export const bool: Requireable<boolean>;
export const string: Requireable<string>;
export const number: Requireable<number>;
export function shape<P extends ValidationMap<any>>(type: P): Requireable<InferProps<P>>;
export function oneOfType<T extends Validator<any>>(types: T[]): Requireable<NonNullable<InferType<T>>>;
//// [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<Props>;
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<typeof propTypes>;
type ExtractedPropsWithoutAnnotation = PropTypes.InferProps<typeof propTypesWithoutAnnotation>;
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;

View file

@ -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<T> = 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<V> = { [K in keyof V]-?: Exclude<V[K], undefined> extends Validator<infer T> ? IsOptional<T> 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<V> = Exclude<keyof V, RequiredKeys<V>>;
>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<V> = { [K in keyof V]-?: InferType<V[K]>; };
>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<T> {
>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<T> extends Validator<T | undefined | null> {
>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<NonNullable<T>>;
>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<T> = { [K in keyof T]?: Validator<T[K]> };
>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> = V extends Validator<infer T> ? 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<V> =
>InferProps : Symbol(InferProps, Decl(index.d.ts, 19, 66))
>V : Symbol(V, Decl(index.d.ts, 20, 23))
& InferPropsInner<Pick<V, RequiredKeys<V>>>
>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<InferPropsInner<Pick<V, OptionalKeys<V>>>>;
>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>;
>any : Symbol(any, Decl(index.d.ts, 24, 12))
>Requireable : Symbol(Requireable, Decl(index.d.ts, 11, 1))
export const array: Requireable<any[]>;
>array : Symbol(array, Decl(index.d.ts, 25, 12))
>Requireable : Symbol(Requireable, Decl(index.d.ts, 11, 1))
export const bool: Requireable<boolean>;
>bool : Symbol(bool, Decl(index.d.ts, 26, 12))
>Requireable : Symbol(Requireable, Decl(index.d.ts, 11, 1))
export const string: Requireable<string>;
>string : Symbol(string, Decl(index.d.ts, 27, 12))
>Requireable : Symbol(Requireable, Decl(index.d.ts, 11, 1))
export const number: Requireable<number>;
>number : Symbol(number, Decl(index.d.ts, 28, 12))
>Requireable : Symbol(Requireable, Decl(index.d.ts, 11, 1))
export function shape<P extends ValidationMap<any>>(type: P): Requireable<InferProps<P>>;
>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<T extends Validator<any>>(types: T[]): Requireable<NonNullable<InferType<T>>>;
>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<Props>;
>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<typeof propTypes>;
>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<typeof propTypesWithoutAnnotation>;
>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))

View file

@ -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<T> = undefined | null extends T ? true : undefined extends T ? true : null extends T ? true : false;
>IsOptional : IsOptional<T>
>null : null
>true : true
>true : true
>null : null
>true : true
>false : false
export type RequiredKeys<V> = { [K in keyof V]-?: Exclude<V[K], undefined> extends Validator<infer T> ? IsOptional<T> extends true ? never : K : never }[keyof V];
>RequiredKeys : { [K in keyof V]-?: Exclude<V[K], undefined> extends Validator<infer T> ? IsOptional<T> extends true ? never : K : never; }[keyof V]
>true : true
export type OptionalKeys<V> = Exclude<keyof V, RequiredKeys<V>>;
>OptionalKeys : Exclude<keyof V, { [K in keyof V]-?: Exclude<V[K], undefined> extends Validator<infer T> ? IsOptional<T> extends true ? never : K : never; }[keyof V]>
export type InferPropsInner<V> = { [K in keyof V]-?: InferType<V[K]>; };
>InferPropsInner : InferPropsInner<V>
export interface Validator<T> {
(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<T> extends Validator<T | undefined | null> {
>null : null
isRequired: Validator<NonNullable<T>>;
>isRequired : Validator<NonNullable<T>>
}
export type ValidationMap<T> = { [K in keyof T]?: Validator<T[K]> };
>ValidationMap : ValidationMap<T>
export type InferType<V> = V extends Validator<infer T> ? T : any;
>InferType : InferType<V>
export type InferProps<V> =
>InferProps : InferProps<V>
& InferPropsInner<Pick<V, RequiredKeys<V>>>
& Partial<InferPropsInner<Pick<V, OptionalKeys<V>>>>;
export const any: Requireable<any>;
>any : Requireable<any>
export const array: Requireable<any[]>;
>array : Requireable<any[]>
export const bool: Requireable<boolean>;
>bool : Requireable<boolean>
export const string: Requireable<string>;
>string : Requireable<string>
export const number: Requireable<number>;
>number : Requireable<number>
export function shape<P extends ValidationMap<any>>(type: P): Requireable<InferProps<P>>;
>shape : <P extends ValidationMap<any>>(type: P) => Requireable<InferProps<P>>
>type : P
export function oneOfType<T extends Validator<any>>(types: T[]): Requireable<NonNullable<InferType<T>>>;
>oneOfType : <T extends Validator<any>>(types: T[]) => Requireable<NonNullable<InferType<T>>>
>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<Props>;
>PropTypesMap : PropTypes.ValidationMap<Props>
>PropTypes : any
const innerProps = {
>innerProps : { foo: PropTypes.Validator<string>; bar: PropTypes.Requireable<boolean>; baz: PropTypes.Requireable<any>; }
>{ foo: PropTypes.string.isRequired, bar: PropTypes.bool, baz: PropTypes.any} : { foo: PropTypes.Validator<string>; bar: PropTypes.Requireable<boolean>; baz: PropTypes.Requireable<any>; }
foo: PropTypes.string.isRequired,
>foo : PropTypes.Validator<string>
>PropTypes.string.isRequired : PropTypes.Validator<string>
>PropTypes.string : PropTypes.Requireable<string>
>PropTypes : typeof PropTypes
>string : PropTypes.Requireable<string>
>isRequired : PropTypes.Validator<string>
bar: PropTypes.bool,
>bar : PropTypes.Requireable<boolean>
>PropTypes.bool : PropTypes.Requireable<boolean>
>PropTypes : typeof PropTypes
>bool : PropTypes.Requireable<boolean>
baz: PropTypes.any
>baz : PropTypes.Requireable<any>
>PropTypes.any : PropTypes.Requireable<any>
>PropTypes : typeof PropTypes
>any : PropTypes.Requireable<any>
};
const arrayOfTypes = [PropTypes.string, PropTypes.bool, PropTypes.shape({
>arrayOfTypes : (PropTypes.Requireable<boolean> | PropTypes.Requireable<string> | PropTypes.Requireable<PropTypes.InferProps<{ foo: PropTypes.Requireable<string>; bar: PropTypes.Validator<number>; }>>)[]
>[PropTypes.string, PropTypes.bool, PropTypes.shape({ foo: PropTypes.string, bar: PropTypes.number.isRequired})] : (PropTypes.Requireable<boolean> | PropTypes.Requireable<string> | PropTypes.Requireable<PropTypes.InferProps<{ foo: PropTypes.Requireable<string>; bar: PropTypes.Validator<number>; }>>)[]
>PropTypes.string : PropTypes.Requireable<string>
>PropTypes : typeof PropTypes
>string : PropTypes.Requireable<string>
>PropTypes.bool : PropTypes.Requireable<boolean>
>PropTypes : typeof PropTypes
>bool : PropTypes.Requireable<boolean>
>PropTypes.shape({ foo: PropTypes.string, bar: PropTypes.number.isRequired}) : PropTypes.Requireable<PropTypes.InferProps<{ foo: PropTypes.Requireable<string>; bar: PropTypes.Validator<number>; }>>
>PropTypes.shape : <P extends PropTypes.ValidationMap<any>>(type: P) => PropTypes.Requireable<PropTypes.InferProps<P>>
>PropTypes : typeof PropTypes
>shape : <P extends PropTypes.ValidationMap<any>>(type: P) => PropTypes.Requireable<PropTypes.InferProps<P>>
>{ foo: PropTypes.string, bar: PropTypes.number.isRequired} : { foo: PropTypes.Requireable<string>; bar: PropTypes.Validator<number>; }
foo: PropTypes.string,
>foo : PropTypes.Requireable<string>
>PropTypes.string : PropTypes.Requireable<string>
>PropTypes : typeof PropTypes
>string : PropTypes.Requireable<string>
bar: PropTypes.number.isRequired
>bar : PropTypes.Validator<number>
>PropTypes.number.isRequired : PropTypes.Validator<number>
>PropTypes.number : PropTypes.Requireable<number>
>PropTypes : typeof PropTypes
>number : PropTypes.Requireable<number>
>isRequired : PropTypes.Validator<number>
})];
// TS checking
const propTypes: PropTypesMap = {
>propTypes : PropTypes.ValidationMap<Props>
>{ any: PropTypes.any, array: PropTypes.array.isRequired, bool: PropTypes.bool.isRequired, shape: PropTypes.shape(innerProps).isRequired, oneOfType: PropTypes.oneOfType(arrayOfTypes).isRequired,} : { any: PropTypes.Requireable<any>; array: PropTypes.Validator<any[]>; bool: PropTypes.Validator<boolean>; shape: PropTypes.Validator<PropTypes.InferProps<{ foo: PropTypes.Validator<string>; bar: PropTypes.Requireable<boolean>; baz: PropTypes.Requireable<any>; }>>; oneOfType: PropTypes.Validator<string | boolean | PropTypes.InferProps<{ foo: PropTypes.Requireable<string>; bar: PropTypes.Validator<number>; }>>; }
any: PropTypes.any,
>any : PropTypes.Requireable<any>
>PropTypes.any : PropTypes.Requireable<any>
>PropTypes : typeof PropTypes
>any : PropTypes.Requireable<any>
array: PropTypes.array.isRequired,
>array : PropTypes.Validator<any[]>
>PropTypes.array.isRequired : PropTypes.Validator<any[]>
>PropTypes.array : PropTypes.Requireable<any[]>
>PropTypes : typeof PropTypes
>array : PropTypes.Requireable<any[]>
>isRequired : PropTypes.Validator<any[]>
bool: PropTypes.bool.isRequired,
>bool : PropTypes.Validator<boolean>
>PropTypes.bool.isRequired : PropTypes.Validator<boolean>
>PropTypes.bool : PropTypes.Requireable<boolean>
>PropTypes : typeof PropTypes
>bool : PropTypes.Requireable<boolean>
>isRequired : PropTypes.Validator<boolean>
shape: PropTypes.shape(innerProps).isRequired,
>shape : PropTypes.Validator<PropTypes.InferProps<{ foo: PropTypes.Validator<string>; bar: PropTypes.Requireable<boolean>; baz: PropTypes.Requireable<any>; }>>
>PropTypes.shape(innerProps).isRequired : PropTypes.Validator<PropTypes.InferProps<{ foo: PropTypes.Validator<string>; bar: PropTypes.Requireable<boolean>; baz: PropTypes.Requireable<any>; }>>
>PropTypes.shape(innerProps) : PropTypes.Requireable<PropTypes.InferProps<{ foo: PropTypes.Validator<string>; bar: PropTypes.Requireable<boolean>; baz: PropTypes.Requireable<any>; }>>
>PropTypes.shape : <P extends PropTypes.ValidationMap<any>>(type: P) => PropTypes.Requireable<PropTypes.InferProps<P>>
>PropTypes : typeof PropTypes
>shape : <P extends PropTypes.ValidationMap<any>>(type: P) => PropTypes.Requireable<PropTypes.InferProps<P>>
>innerProps : { foo: PropTypes.Validator<string>; bar: PropTypes.Requireable<boolean>; baz: PropTypes.Requireable<any>; }
>isRequired : PropTypes.Validator<PropTypes.InferProps<{ foo: PropTypes.Validator<string>; bar: PropTypes.Requireable<boolean>; baz: PropTypes.Requireable<any>; }>>
oneOfType: PropTypes.oneOfType(arrayOfTypes).isRequired,
>oneOfType : PropTypes.Validator<string | boolean | PropTypes.InferProps<{ foo: PropTypes.Requireable<string>; bar: PropTypes.Validator<number>; }>>
>PropTypes.oneOfType(arrayOfTypes).isRequired : PropTypes.Validator<string | boolean | PropTypes.InferProps<{ foo: PropTypes.Requireable<string>; bar: PropTypes.Validator<number>; }>>
>PropTypes.oneOfType(arrayOfTypes) : PropTypes.Requireable<string | boolean | PropTypes.InferProps<{ foo: PropTypes.Requireable<string>; bar: PropTypes.Validator<number>; }>>
>PropTypes.oneOfType : <T extends PropTypes.Validator<any>>(types: T[]) => PropTypes.Requireable<NonNullable<PropTypes.InferType<T>>>
>PropTypes : typeof PropTypes
>oneOfType : <T extends PropTypes.Validator<any>>(types: T[]) => PropTypes.Requireable<NonNullable<PropTypes.InferType<T>>>
>arrayOfTypes : (PropTypes.Requireable<boolean> | PropTypes.Requireable<string> | PropTypes.Requireable<PropTypes.InferProps<{ foo: PropTypes.Requireable<string>; bar: PropTypes.Validator<number>; }>>)[]
>isRequired : PropTypes.Validator<string | boolean | PropTypes.InferProps<{ foo: PropTypes.Requireable<string>; bar: PropTypes.Validator<number>; }>>
};
// JS checking
const propTypesWithoutAnnotation = {
>propTypesWithoutAnnotation : { any: PropTypes.Requireable<any>; array: PropTypes.Validator<any[]>; bool: PropTypes.Validator<boolean>; shape: PropTypes.Validator<PropTypes.InferProps<{ foo: PropTypes.Validator<string>; bar: PropTypes.Requireable<boolean>; baz: PropTypes.Requireable<any>; }>>; oneOfType: PropTypes.Validator<string | boolean | PropTypes.InferProps<{ foo: PropTypes.Requireable<string>; bar: PropTypes.Validator<number>; }>>; }
>{ any: PropTypes.any, array: PropTypes.array.isRequired, bool: PropTypes.bool.isRequired, shape: PropTypes.shape(innerProps).isRequired, oneOfType: PropTypes.oneOfType(arrayOfTypes).isRequired,} : { any: PropTypes.Requireable<any>; array: PropTypes.Validator<any[]>; bool: PropTypes.Validator<boolean>; shape: PropTypes.Validator<PropTypes.InferProps<{ foo: PropTypes.Validator<string>; bar: PropTypes.Requireable<boolean>; baz: PropTypes.Requireable<any>; }>>; oneOfType: PropTypes.Validator<string | boolean | PropTypes.InferProps<{ foo: PropTypes.Requireable<string>; bar: PropTypes.Validator<number>; }>>; }
any: PropTypes.any,
>any : PropTypes.Requireable<any>
>PropTypes.any : PropTypes.Requireable<any>
>PropTypes : typeof PropTypes
>any : PropTypes.Requireable<any>
array: PropTypes.array.isRequired,
>array : PropTypes.Validator<any[]>
>PropTypes.array.isRequired : PropTypes.Validator<any[]>
>PropTypes.array : PropTypes.Requireable<any[]>
>PropTypes : typeof PropTypes
>array : PropTypes.Requireable<any[]>
>isRequired : PropTypes.Validator<any[]>
bool: PropTypes.bool.isRequired,
>bool : PropTypes.Validator<boolean>
>PropTypes.bool.isRequired : PropTypes.Validator<boolean>
>PropTypes.bool : PropTypes.Requireable<boolean>
>PropTypes : typeof PropTypes
>bool : PropTypes.Requireable<boolean>
>isRequired : PropTypes.Validator<boolean>
shape: PropTypes.shape(innerProps).isRequired,
>shape : PropTypes.Validator<PropTypes.InferProps<{ foo: PropTypes.Validator<string>; bar: PropTypes.Requireable<boolean>; baz: PropTypes.Requireable<any>; }>>
>PropTypes.shape(innerProps).isRequired : PropTypes.Validator<PropTypes.InferProps<{ foo: PropTypes.Validator<string>; bar: PropTypes.Requireable<boolean>; baz: PropTypes.Requireable<any>; }>>
>PropTypes.shape(innerProps) : PropTypes.Requireable<PropTypes.InferProps<{ foo: PropTypes.Validator<string>; bar: PropTypes.Requireable<boolean>; baz: PropTypes.Requireable<any>; }>>
>PropTypes.shape : <P extends PropTypes.ValidationMap<any>>(type: P) => PropTypes.Requireable<PropTypes.InferProps<P>>
>PropTypes : typeof PropTypes
>shape : <P extends PropTypes.ValidationMap<any>>(type: P) => PropTypes.Requireable<PropTypes.InferProps<P>>
>innerProps : { foo: PropTypes.Validator<string>; bar: PropTypes.Requireable<boolean>; baz: PropTypes.Requireable<any>; }
>isRequired : PropTypes.Validator<PropTypes.InferProps<{ foo: PropTypes.Validator<string>; bar: PropTypes.Requireable<boolean>; baz: PropTypes.Requireable<any>; }>>
oneOfType: PropTypes.oneOfType(arrayOfTypes).isRequired,
>oneOfType : PropTypes.Validator<string | boolean | PropTypes.InferProps<{ foo: PropTypes.Requireable<string>; bar: PropTypes.Validator<number>; }>>
>PropTypes.oneOfType(arrayOfTypes).isRequired : PropTypes.Validator<string | boolean | PropTypes.InferProps<{ foo: PropTypes.Requireable<string>; bar: PropTypes.Validator<number>; }>>
>PropTypes.oneOfType(arrayOfTypes) : PropTypes.Requireable<string | boolean | PropTypes.InferProps<{ foo: PropTypes.Requireable<string>; bar: PropTypes.Validator<number>; }>>
>PropTypes.oneOfType : <T extends PropTypes.Validator<any>>(types: T[]) => PropTypes.Requireable<NonNullable<PropTypes.InferType<T>>>
>PropTypes : typeof PropTypes
>oneOfType : <T extends PropTypes.Validator<any>>(types: T[]) => PropTypes.Requireable<NonNullable<PropTypes.InferType<T>>>
>arrayOfTypes : (PropTypes.Requireable<boolean> | PropTypes.Requireable<string> | PropTypes.Requireable<PropTypes.InferProps<{ foo: PropTypes.Requireable<string>; bar: PropTypes.Validator<number>; }>>)[]
>isRequired : PropTypes.Validator<string | boolean | PropTypes.InferProps<{ foo: PropTypes.Requireable<string>; bar: PropTypes.Validator<number>; }>>
};
type ExtractedProps = PropTypes.InferProps<typeof propTypes>;
>ExtractedProps : PropTypes.InferProps<PropTypes.ValidationMap<Props>>
>PropTypes : any
>propTypes : PropTypes.ValidationMap<Props>
type ExtractedPropsWithoutAnnotation = PropTypes.InferProps<typeof propTypesWithoutAnnotation>;
>ExtractedPropsWithoutAnnotation : PropTypes.InferProps<{ any: PropTypes.Requireable<any>; array: PropTypes.Validator<any[]>; bool: PropTypes.Validator<boolean>; shape: PropTypes.Validator<PropTypes.InferProps<{ foo: PropTypes.Validator<string>; bar: PropTypes.Requireable<boolean>; baz: PropTypes.Requireable<any>; }>>; oneOfType: PropTypes.Validator<string | boolean | PropTypes.InferProps<{ foo: PropTypes.Requireable<string>; bar: PropTypes.Validator<number>; }>>; }>
>PropTypes : any
>propTypesWithoutAnnotation : { any: PropTypes.Requireable<any>; array: PropTypes.Validator<any[]>; bool: PropTypes.Validator<boolean>; shape: PropTypes.Validator<PropTypes.InferProps<{ foo: PropTypes.Validator<string>; bar: PropTypes.Requireable<boolean>; baz: PropTypes.Requireable<any>; }>>; oneOfType: PropTypes.Validator<string | boolean | PropTypes.InferProps<{ foo: PropTypes.Requireable<string>; bar: PropTypes.Validator<number>; }>>; }
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

View file

@ -0,0 +1,65 @@
// @strict: true
const fn1 = <Params>(
params: Pick<Params, Exclude<keyof Params, never>>,
): Params => params;
function fn2<T>(x: Exclude<T, never>) {
var y: T = x;
x = y;
}
const fn3 = <Params>(
params: Pick<Params, Extract<keyof Params, keyof Params>>,
): Params => params;
function fn4<T>(x: Extract<T, T>) {
var y: T = x;
x = y;
}
declare var x: Extract<number | string, any>; // Should be `numebr | string` and not `any`
type ExtractWithDefault<T, U, D = never> = T extends U ? T : D;
type ExcludeWithDefault<T, U, D = never> = T extends U ? D : T;
const fn5 = <Params>(
params: Pick<Params, ExcludeWithDefault<keyof Params, never>>,
): Params => params;
function fn6<T>(x: ExcludeWithDefault<T, never>) {
var y: T = x;
x = y;
}
const fn7 = <Params>(
params: Pick<Params, ExtractWithDefault<keyof Params, keyof Params>>,
): Params => params;
function fn8<T>(x: ExtractWithDefault<T, T>) {
var y: T = x;
x = y;
}
type TemplatedConditional<TCheck, TExtends, TTrue, TFalse> = TCheck extends TExtends ? TTrue : TFalse;
const fn9 = <Params>(
params: Pick<Params, TemplatedConditional<keyof Params, never, never, keyof Params>>,
): Params => params;
function fn10<T>(x: TemplatedConditional<T, never, never, T>) {
var y: T = x;
x = y;
}
const fn11 = <Params>(
params: Pick<Params, TemplatedConditional<keyof Params, keyof Params, keyof Params, never>>,
): Params => params;
function fn12<T>(x: TemplatedConditional<T, T, T, never>) {
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`

View file

@ -0,0 +1,89 @@
// @strict: true
// @filename: node_modules/prop-types/index.d.ts
export const nominalTypeHack: unique symbol;
export type IsOptional<T> = undefined | null extends T ? true : undefined extends T ? true : null extends T ? true : false;
export type RequiredKeys<V> = { [K in keyof V]-?: Exclude<V[K], undefined> extends Validator<infer T> ? IsOptional<T> extends true ? never : K : never }[keyof V];
export type OptionalKeys<V> = Exclude<keyof V, RequiredKeys<V>>;
export type InferPropsInner<V> = { [K in keyof V]-?: InferType<V[K]>; };
export interface Validator<T> {
(props: object, propName: string, componentName: string, location: string, propFullName: string): Error | null;
[nominalTypeHack]?: T;
}
export interface Requireable<T> extends Validator<T | undefined | null> {
isRequired: Validator<NonNullable<T>>;
}
export type ValidationMap<T> = { [K in keyof T]?: Validator<T[K]> };
export type InferType<V> = V extends Validator<infer T> ? T : any;
export type InferProps<V> =
& InferPropsInner<Pick<V, RequiredKeys<V>>>
& Partial<InferPropsInner<Pick<V, OptionalKeys<V>>>>;
export const any: Requireable<any>;
export const array: Requireable<any[]>;
export const bool: Requireable<boolean>;
export const string: Requireable<string>;
export const number: Requireable<number>;
export function shape<P extends ValidationMap<any>>(type: P): Requireable<InferProps<P>>;
export function oneOfType<T extends Validator<any>>(types: T[]): Requireable<NonNullable<InferType<T>>>;
// @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<Props>;
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<typeof propTypes>;
type ExtractedPropsWithoutAnnotation = PropTypes.InferProps<typeof propTypesWithoutAnnotation>;
type ExtractPropsMatch = ExtractedProps extends ExtractedPropsWithoutAnnotation ? true : false;
const x: true = (null as any as ExtractPropsMatch);