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:
parent
6607e00b8f
commit
a9ad94ab3c
|
@ -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 {
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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 };
|
||||
|
|
100
tests/baselines/reference/conditionalTypesSimplifyWhenTrivial.js
Normal file
100
tests/baselines/reference/conditionalTypesSimplifyWhenTrivial.js
Normal 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`
|
|
@ -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))
|
||||
|
|
@ -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
|
||||
|
121
tests/baselines/reference/propTypeValidatorInference.js
Normal file
121
tests/baselines/reference/propTypeValidatorInference.js
Normal 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;
|
366
tests/baselines/reference/propTypeValidatorInference.symbols
Normal file
366
tests/baselines/reference/propTypeValidatorInference.symbols
Normal 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))
|
||||
|
301
tests/baselines/reference/propTypeValidatorInference.types
Normal file
301
tests/baselines/reference/propTypeValidatorInference.types
Normal 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
|
||||
|
65
tests/cases/compiler/conditionalTypesSimplifyWhenTrivial.ts
Normal file
65
tests/cases/compiler/conditionalTypesSimplifyWhenTrivial.ts
Normal 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`
|
89
tests/cases/compiler/propTypeValidatorInference.ts
Normal file
89
tests/cases/compiler/propTypeValidatorInference.ts
Normal 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);
|
Loading…
Reference in a new issue