Merge pull request #21709 from Microsoft/inferredTypeParameterConstraints

Inferred type parameter constraints
This commit is contained in:
Anders Hejlsberg
2018-02-07 13:16:07 -08:00
committed by GitHub
7 changed files with 498 additions and 112 deletions
+98 -49
View File
@@ -6963,6 +6963,42 @@ namespace ts {
return type.symbol && getDeclarationOfKind<TypeParameterDeclaration>(type.symbol, SyntaxKind.TypeParameter).constraint;
}
function getInferredTypeParameterConstraint(typeParameter: TypeParameter) {
let inferences: Type[];
if (typeParameter.symbol) {
for (const declaration of typeParameter.symbol.declarations) {
// When an 'infer T' declaration is immediately contained in a type reference node
// (such as 'Foo<infer T>'), T's constraint is inferred from the constraint of the
// corresponding type parameter in 'Foo'. When multiple 'infer T' declarations are
// present, we form an intersection of the inferred constraint types.
if (declaration.parent.kind === SyntaxKind.InferType && declaration.parent.parent.kind === SyntaxKind.TypeReference) {
const typeReference = <TypeReferenceNode>declaration.parent.parent;
const typeParameters = getTypeParametersForTypeReference(typeReference);
if (typeParameters) {
const index = typeReference.typeArguments.indexOf(<TypeNode>declaration.parent);
if (index < typeParameters.length) {
const declaredConstraint = getConstraintOfTypeParameter(typeParameters[index]);
if (declaredConstraint) {
// Type parameter constraints can reference other type parameters so
// constraints need to be instantiated. If instantiation produces the
// type parameter itself, we discard that inference. For example, in
// type Foo<T extends string, U extends T> = [T, U];
// type Bar<T> = T extends Foo<infer X, infer X> ? Foo<X, X> : T;
// the instantiated constraint for U is X, so we discard that inference.
const mapper = createTypeMapper(typeParameters, getEffectiveTypeArguments(typeReference, typeParameters));
const constraint = instantiateType(declaredConstraint, mapper);
if (constraint !== typeParameter) {
inferences = append(inferences, constraint);
}
}
}
}
}
}
}
return inferences && getIntersectionType(inferences);
}
function getConstraintFromTypeParameter(typeParameter: TypeParameter): Type {
if (!typeParameter.constraint) {
if (typeParameter.target) {
@@ -6971,7 +7007,8 @@ namespace ts {
}
else {
const constraintDeclaration = getConstraintDeclaration(typeParameter);
typeParameter.constraint = constraintDeclaration ? getTypeFromTypeNode(constraintDeclaration) : noConstraintType;
typeParameter.constraint = constraintDeclaration ? getTypeFromTypeNode(constraintDeclaration) :
getInferredTypeParameterConstraint(typeParameter) || noConstraintType;
}
}
return typeParameter.constraint === noConstraintType ? undefined : typeParameter.constraint;
@@ -7078,12 +7115,8 @@ namespace ts {
const typeArguments = concatenate(type.outerTypeParameters, fillMissingTypeArguments(typeArgs, typeParameters, minTypeArgumentCount, isJs));
return createTypeReference(<GenericType>type, typeArguments);
}
if (node.typeArguments) {
error(node, Diagnostics.Type_0_is_not_generic, typeToString(type));
return unknownType;
return checkNoTypeArguments(node, symbol) ? type : unknownType;
}
return type;
}
function getTypeAliasInstantiation(symbol: Symbol, typeArguments: Type[]): Type {
const type = getDeclaredTypeOfSymbol(symbol);
@@ -7120,12 +7153,8 @@ namespace ts {
}
return getTypeAliasInstantiation(symbol, typeArguments);
}
if (node.typeArguments) {
error(node, Diagnostics.Type_0_is_not_generic, symbolToString(symbol));
return unknownType;
return checkNoTypeArguments(node, symbol) ? type : unknownType;
}
return type;
}
function getTypeReferenceName(node: TypeReferenceType): EntityNameOrEntityNameExpression | undefined {
switch (node.kind) {
@@ -7165,12 +7194,10 @@ namespace ts {
// Get type from reference to named type that cannot be generic (enum or type parameter)
const res = tryGetDeclaredTypeOfSymbol(symbol);
if (res !== undefined) {
if (typeArguments) {
error(node, Diagnostics.Type_0_is_not_generic, symbolToString(symbol));
return unknownType;
}
return res.flags & TypeFlags.TypeParameter ? getConstrainedTypeParameter(<TypeParameter>res, node) : res;
if (res) {
return checkNoTypeArguments(node, symbol) ?
res.flags & TypeFlags.TypeParameter ? getConstrainedTypeParameter(<TypeParameter>res, node) : res :
unknownType;
}
if (!(symbol.flags & SymbolFlags.Value && isJSDocTypeReference(node))) {
@@ -7234,39 +7261,58 @@ namespace ts {
return node.flags & NodeFlags.JSDoc && node.kind === SyntaxKind.TypeReference;
}
function checkNoTypeArguments(node: TypeReferenceType, symbol?: Symbol) {
if (node.typeArguments) {
error(node, Diagnostics.Type_0_is_not_generic, symbol ? symbolToString(symbol) : declarationNameToString((<TypeReferenceNode>node).typeName));
return false;
}
return true;
}
function getIntendedTypeFromJSDocTypeReference(node: TypeReferenceNode): Type {
if (isIdentifier(node.typeName)) {
if (node.typeName.escapedText === "Object") {
if (isJSDocIndexSignature(node)) {
const indexed = getTypeFromTypeNode(node.typeArguments[0]);
const target = getTypeFromTypeNode(node.typeArguments[1]);
const index = createIndexInfo(target, /*isReadonly*/ false);
return createAnonymousType(undefined, emptySymbols, emptyArray, emptyArray, indexed === stringType && index, indexed === numberType && index);
}
return anyType;
}
const typeArgs = node.typeArguments;
switch (node.typeName.escapedText) {
case "String":
checkNoTypeArguments(node);
return stringType;
case "Number":
checkNoTypeArguments(node);
return numberType;
case "Boolean":
checkNoTypeArguments(node);
return booleanType;
case "Void":
checkNoTypeArguments(node);
return voidType;
case "Undefined":
checkNoTypeArguments(node);
return undefinedType;
case "Null":
checkNoTypeArguments(node);
return nullType;
case "Function":
case "function":
checkNoTypeArguments(node);
return globalFunctionType;
case "Array":
case "array":
return !node.typeArguments || !node.typeArguments.length ? anyArrayType : undefined;
return !typeArgs || !typeArgs.length ? anyArrayType : undefined;
case "Promise":
case "promise":
return !node.typeArguments || !node.typeArguments.length ? createPromiseType(anyType) : undefined;
return !typeArgs || !typeArgs.length ? createPromiseType(anyType) : undefined;
case "Object":
if (typeArgs && typeArgs.length === 2) {
if (isJSDocIndexSignature(node)) {
const indexed = getTypeFromTypeNode(typeArgs[0]);
const target = getTypeFromTypeNode(typeArgs[1]);
const index = createIndexInfo(target, /*isReadonly*/ false);
return createAnonymousType(undefined, emptySymbols, emptyArray, emptyArray, indexed === stringType && index, indexed === numberType && index);
}
return anyType;
}
checkNoTypeArguments(node);
return anyType;
}
}
}
@@ -20148,8 +20194,12 @@ namespace ts {
checkDecorators(node);
}
function checkTypeArgumentConstraints(typeParameters: TypeParameter[], typeArgumentNodes: ReadonlyArray<TypeNode>): boolean {
const minTypeArgumentCount = getMinTypeArgumentCount(typeParameters);
function getEffectiveTypeArguments(node: TypeReferenceNode | ExpressionWithTypeArguments, typeParameters: TypeParameter[]) {
return fillMissingTypeArguments(map(node.typeArguments, getTypeFromTypeNode), typeParameters,
getMinTypeArgumentCount(typeParameters), isInJavaScriptFile(node));
}
function checkTypeArgumentConstraints(node: TypeReferenceNode | ExpressionWithTypeArguments, typeParameters: TypeParameter[]): boolean {
let typeArguments: Type[];
let mapper: TypeMapper;
let result = true;
@@ -20157,25 +20207,36 @@ namespace ts {
const constraint = getConstraintOfTypeParameter(typeParameters[i]);
if (constraint) {
if (!typeArguments) {
typeArguments = fillMissingTypeArguments(map(typeArgumentNodes, getTypeFromTypeNode), typeParameters, minTypeArgumentCount, isInJavaScriptFile(typeArgumentNodes[i]));
typeArguments = getEffectiveTypeArguments(node, typeParameters);
mapper = createTypeMapper(typeParameters, typeArguments);
}
const typeArgument = typeArguments[i];
result = result && checkTypeAssignableTo(
typeArgument,
instantiateType(constraint, mapper),
typeArgumentNodes[i],
node.typeArguments[i],
Diagnostics.Type_0_does_not_satisfy_the_constraint_1);
}
}
return result;
}
function getTypeParametersForTypeReference(node: TypeReferenceNode | ExpressionWithTypeArguments) {
const type = getTypeFromTypeReference(node);
if (type !== unknownType) {
const symbol = getNodeLinks(node).resolvedSymbol;
if (symbol) {
return symbol.flags & SymbolFlags.TypeAlias && getSymbolLinks(symbol).typeParameters ||
(getObjectFlags(type) & ObjectFlags.Reference ? (<TypeReference>type).target.localTypeParameters : undefined);
}
}
return undefined;
}
function checkTypeReferenceNode(node: TypeReferenceNode | ExpressionWithTypeArguments) {
checkGrammarTypeArguments(node, node.typeArguments);
if (node.kind === SyntaxKind.TypeReference && node.typeName.jsdocDotPos !== undefined && !isInJavaScriptFile(node) && !isInJSDoc(node)) {
grammarErrorAtPos(node, node.typeName.jsdocDotPos, 1, Diagnostics.JSDoc_types_can_only_be_used_inside_documentation_comments);
}
const type = getTypeFromTypeReference(node);
if (type !== unknownType) {
@@ -20183,22 +20244,10 @@ namespace ts {
// Do type argument local checks only if referenced type is successfully resolved
forEach(node.typeArguments, checkSourceElement);
if (produceDiagnostics) {
const symbol = getNodeLinks(node).resolvedSymbol;
if (!symbol) {
// There is no resolved symbol cached if the type resolved to a builtin
// via JSDoc type reference resolution (eg, Boolean became boolean), none
// of which are generic when they have no associated symbol
// (additionally, JSDoc's index signature syntax, Object<string, T> actually uses generic syntax without being generic)
if (!isJSDocIndexSignature(node)) {
error(node, Diagnostics.Type_0_is_not_generic, typeToString(type));
}
return;
const typeParameters = getTypeParametersForTypeReference(node);
if (typeParameters) {
checkTypeArgumentConstraints(node, typeParameters);
}
let typeParameters = symbol.flags & SymbolFlags.TypeAlias && getSymbolLinks(symbol).typeParameters;
if (!typeParameters && getObjectFlags(type) & ObjectFlags.Reference) {
typeParameters = (<TypeReference>type).target.localTypeParameters;
}
checkTypeArgumentConstraints(typeParameters, node.typeArguments);
}
}
if (type.flags & TypeFlags.Enum && getNodeLinks(node).resolvedSymbol.flags & SymbolFlags.EnumMember) {
@@ -22895,7 +22944,7 @@ namespace ts {
if (some(baseTypeNode.typeArguments)) {
forEach(baseTypeNode.typeArguments, checkSourceElement);
for (const constructor of getConstructorsForTypeArguments(staticBaseType, baseTypeNode.typeArguments, baseTypeNode)) {
if (!checkTypeArgumentConstraints(constructor.typeParameters, baseTypeNode.typeArguments)) {
if (!checkTypeArgumentConstraints(baseTypeNode, constructor.typeParameters)) {
break;
}
}
@@ -10,9 +10,11 @@ tests/cases/conformance/types/conditional/inferTypes1.ts(72,15): error TS2304: C
tests/cases/conformance/types/conditional/inferTypes1.ts(72,15): error TS4081: Exported type alias 'T62' has or is using private name 'U'.
tests/cases/conformance/types/conditional/inferTypes1.ts(72,43): error TS2304: Cannot find name 'U'.
tests/cases/conformance/types/conditional/inferTypes1.ts(72,43): error TS4081: Exported type alias 'T62' has or is using private name 'U'.
tests/cases/conformance/types/conditional/inferTypes1.ts(78,44): error TS2344: Type 'U' does not satisfy the constraint 'string'.
Type 'number' is not assignable to type 'string'.
==== tests/cases/conformance/types/conditional/inferTypes1.ts (11 errors) ====
==== tests/cases/conformance/types/conditional/inferTypes1.ts (12 errors) ====
type Unpacked<T> =
T extends (infer U)[] ? U :
T extends (...args: any[]) => infer U ? U :
@@ -109,6 +111,22 @@ tests/cases/conformance/types/conditional/inferTypes1.ts(72,43): error TS4081: E
~
!!! error TS4081: Exported type alias 'T62' has or is using private name 'U'.
type T70<T extends string> = { x: T };
type T71<T> = T extends T70<infer U> ? T70<U> : never;
type T72<T extends number> = { y: T };
type T73<T> = T extends T72<infer U> ? T70<U> : never; // Error
~
!!! error TS2344: Type 'U' does not satisfy the constraint 'string'.
!!! error TS2344: Type 'number' is not assignable to type 'string'.
type T74<T extends number, U extends string> = { x: T, y: U };
type T75<T> = T extends T74<infer U, infer U> ? T70<U> | T72<U> | T74<U, U> : never;
type T76<T extends T[], U extends T> = { x: T };
type T77<T> = T extends T76<infer X, infer Y> ? T76<X, Y> : never;
type T78<T> = T extends T76<infer X, infer X> ? T76<X, X> : never;
// Example from #21496
type JsonifiedObject<T extends object> = { [K in keyof T]: Jsonified<T[K]> };
@@ -140,4 +158,13 @@ tests/cases/conformance/types/conditional/inferTypes1.ts(72,43): error TS4081: E
declare let ex: JsonifiedExample;
const z1: "correct" = ex.customClass;
const z2: string = ex.obj.nested.attr;
// Repros from #21631
type A1<T, U extends A1<any, any>> = [T, U];
type B1<S> = S extends A1<infer T, infer U> ? [T, U] : never;
type A2<T, U extends void> = [T, U];
type B2<S> = S extends A2<infer T, infer U> ? [T, U] : never;
type C2<S, U extends void> = S extends A2<infer T, U> ? [T, U] : never;
+22
View File
@@ -72,6 +72,19 @@ type T60 = infer U; // Error
type T61<T> = infer A extends infer B ? infer C : infer D; // Error
type T62<T> = U extends (infer U)[] ? U : U; // Error
type T70<T extends string> = { x: T };
type T71<T> = T extends T70<infer U> ? T70<U> : never;
type T72<T extends number> = { y: T };
type T73<T> = T extends T72<infer U> ? T70<U> : never; // Error
type T74<T extends number, U extends string> = { x: T, y: U };
type T75<T> = T extends T74<infer U, infer U> ? T70<U> | T72<U> | T74<U, U> : never;
type T76<T extends T[], U extends T> = { x: T };
type T77<T> = T extends T76<infer X, infer Y> ? T76<X, Y> : never;
type T78<T> = T extends T76<infer X, infer X> ? T76<X, X> : never;
// Example from #21496
type JsonifiedObject<T extends object> = { [K in keyof T]: Jsonified<T[K]> };
@@ -103,6 +116,15 @@ type JsonifiedExample = Jsonified<Example>;
declare let ex: JsonifiedExample;
const z1: "correct" = ex.customClass;
const z2: string = ex.obj.nested.attr;
// Repros from #21631
type A1<T, U extends A1<any, any>> = [T, U];
type B1<S> = S extends A1<infer T, infer U> ? [T, U] : never;
type A2<T, U extends void> = [T, U];
type B2<S> = S extends A2<infer T, infer U> ? [T, U] : never;
type C2<S, U extends void> = S extends A2<infer T, U> ? [T, U] : never;
//// [inferTypes1.js]
+183 -50
View File
@@ -315,106 +315,239 @@ type T62<T> = U extends (infer U)[] ? U : U; // Error
>U : Symbol(U, Decl(inferTypes1.ts, 71, 30))
>U : Symbol(U, Decl(inferTypes1.ts, 71, 30))
type T70<T extends string> = { x: T };
>T70 : Symbol(T70, Decl(inferTypes1.ts, 71, 44))
>T : Symbol(T, Decl(inferTypes1.ts, 73, 9))
>x : Symbol(x, Decl(inferTypes1.ts, 73, 30))
>T : Symbol(T, Decl(inferTypes1.ts, 73, 9))
type T71<T> = T extends T70<infer U> ? T70<U> : never;
>T71 : Symbol(T71, Decl(inferTypes1.ts, 73, 38))
>T : Symbol(T, Decl(inferTypes1.ts, 74, 9))
>T : Symbol(T, Decl(inferTypes1.ts, 74, 9))
>T70 : Symbol(T70, Decl(inferTypes1.ts, 71, 44))
>U : Symbol(U, Decl(inferTypes1.ts, 74, 33))
>T70 : Symbol(T70, Decl(inferTypes1.ts, 71, 44))
>U : Symbol(U, Decl(inferTypes1.ts, 74, 33))
type T72<T extends number> = { y: T };
>T72 : Symbol(T72, Decl(inferTypes1.ts, 74, 54))
>T : Symbol(T, Decl(inferTypes1.ts, 76, 9))
>y : Symbol(y, Decl(inferTypes1.ts, 76, 30))
>T : Symbol(T, Decl(inferTypes1.ts, 76, 9))
type T73<T> = T extends T72<infer U> ? T70<U> : never; // Error
>T73 : Symbol(T73, Decl(inferTypes1.ts, 76, 38))
>T : Symbol(T, Decl(inferTypes1.ts, 77, 9))
>T : Symbol(T, Decl(inferTypes1.ts, 77, 9))
>T72 : Symbol(T72, Decl(inferTypes1.ts, 74, 54))
>U : Symbol(U, Decl(inferTypes1.ts, 77, 33))
>T70 : Symbol(T70, Decl(inferTypes1.ts, 71, 44))
>U : Symbol(U, Decl(inferTypes1.ts, 77, 33))
type T74<T extends number, U extends string> = { x: T, y: U };
>T74 : Symbol(T74, Decl(inferTypes1.ts, 77, 54))
>T : Symbol(T, Decl(inferTypes1.ts, 79, 9))
>U : Symbol(U, Decl(inferTypes1.ts, 79, 26))
>x : Symbol(x, Decl(inferTypes1.ts, 79, 48))
>T : Symbol(T, Decl(inferTypes1.ts, 79, 9))
>y : Symbol(y, Decl(inferTypes1.ts, 79, 54))
>U : Symbol(U, Decl(inferTypes1.ts, 79, 26))
type T75<T> = T extends T74<infer U, infer U> ? T70<U> | T72<U> | T74<U, U> : never;
>T75 : Symbol(T75, Decl(inferTypes1.ts, 79, 62))
>T : Symbol(T, Decl(inferTypes1.ts, 80, 9))
>T : Symbol(T, Decl(inferTypes1.ts, 80, 9))
>T74 : Symbol(T74, Decl(inferTypes1.ts, 77, 54))
>U : Symbol(U, Decl(inferTypes1.ts, 80, 33), Decl(inferTypes1.ts, 80, 42))
>U : Symbol(U, Decl(inferTypes1.ts, 80, 33), Decl(inferTypes1.ts, 80, 42))
>T70 : Symbol(T70, Decl(inferTypes1.ts, 71, 44))
>U : Symbol(U, Decl(inferTypes1.ts, 80, 33), Decl(inferTypes1.ts, 80, 42))
>T72 : Symbol(T72, Decl(inferTypes1.ts, 74, 54))
>U : Symbol(U, Decl(inferTypes1.ts, 80, 33), Decl(inferTypes1.ts, 80, 42))
>T74 : Symbol(T74, Decl(inferTypes1.ts, 77, 54))
>U : Symbol(U, Decl(inferTypes1.ts, 80, 33), Decl(inferTypes1.ts, 80, 42))
>U : Symbol(U, Decl(inferTypes1.ts, 80, 33), Decl(inferTypes1.ts, 80, 42))
type T76<T extends T[], U extends T> = { x: T };
>T76 : Symbol(T76, Decl(inferTypes1.ts, 80, 84))
>T : Symbol(T, Decl(inferTypes1.ts, 82, 9))
>T : Symbol(T, Decl(inferTypes1.ts, 82, 9))
>U : Symbol(U, Decl(inferTypes1.ts, 82, 23))
>T : Symbol(T, Decl(inferTypes1.ts, 82, 9))
>x : Symbol(x, Decl(inferTypes1.ts, 82, 40))
>T : Symbol(T, Decl(inferTypes1.ts, 82, 9))
type T77<T> = T extends T76<infer X, infer Y> ? T76<X, Y> : never;
>T77 : Symbol(T77, Decl(inferTypes1.ts, 82, 48))
>T : Symbol(T, Decl(inferTypes1.ts, 83, 9))
>T : Symbol(T, Decl(inferTypes1.ts, 83, 9))
>T76 : Symbol(T76, Decl(inferTypes1.ts, 80, 84))
>X : Symbol(X, Decl(inferTypes1.ts, 83, 33))
>Y : Symbol(Y, Decl(inferTypes1.ts, 83, 42))
>T76 : Symbol(T76, Decl(inferTypes1.ts, 80, 84))
>X : Symbol(X, Decl(inferTypes1.ts, 83, 33))
>Y : Symbol(Y, Decl(inferTypes1.ts, 83, 42))
type T78<T> = T extends T76<infer X, infer X> ? T76<X, X> : never;
>T78 : Symbol(T78, Decl(inferTypes1.ts, 83, 66))
>T : Symbol(T, Decl(inferTypes1.ts, 84, 9))
>T : Symbol(T, Decl(inferTypes1.ts, 84, 9))
>T76 : Symbol(T76, Decl(inferTypes1.ts, 80, 84))
>X : Symbol(X, Decl(inferTypes1.ts, 84, 33), Decl(inferTypes1.ts, 84, 42))
>X : Symbol(X, Decl(inferTypes1.ts, 84, 33), Decl(inferTypes1.ts, 84, 42))
>T76 : Symbol(T76, Decl(inferTypes1.ts, 80, 84))
>X : Symbol(X, Decl(inferTypes1.ts, 84, 33), Decl(inferTypes1.ts, 84, 42))
>X : Symbol(X, Decl(inferTypes1.ts, 84, 33), Decl(inferTypes1.ts, 84, 42))
// Example from #21496
type JsonifiedObject<T extends object> = { [K in keyof T]: Jsonified<T[K]> };
>JsonifiedObject : Symbol(JsonifiedObject, Decl(inferTypes1.ts, 71, 44))
>T : Symbol(T, Decl(inferTypes1.ts, 75, 21))
>K : Symbol(K, Decl(inferTypes1.ts, 75, 44))
>T : Symbol(T, Decl(inferTypes1.ts, 75, 21))
>Jsonified : Symbol(Jsonified, Decl(inferTypes1.ts, 75, 77))
>T : Symbol(T, Decl(inferTypes1.ts, 75, 21))
>K : Symbol(K, Decl(inferTypes1.ts, 75, 44))
>JsonifiedObject : Symbol(JsonifiedObject, Decl(inferTypes1.ts, 84, 66))
>T : Symbol(T, Decl(inferTypes1.ts, 88, 21))
>K : Symbol(K, Decl(inferTypes1.ts, 88, 44))
>T : Symbol(T, Decl(inferTypes1.ts, 88, 21))
>Jsonified : Symbol(Jsonified, Decl(inferTypes1.ts, 88, 77))
>T : Symbol(T, Decl(inferTypes1.ts, 88, 21))
>K : Symbol(K, Decl(inferTypes1.ts, 88, 44))
type Jsonified<T> =
>Jsonified : Symbol(Jsonified, Decl(inferTypes1.ts, 75, 77))
>T : Symbol(T, Decl(inferTypes1.ts, 77, 15))
>Jsonified : Symbol(Jsonified, Decl(inferTypes1.ts, 88, 77))
>T : Symbol(T, Decl(inferTypes1.ts, 90, 15))
T extends string | number | boolean | null ? T
>T : Symbol(T, Decl(inferTypes1.ts, 77, 15))
>T : Symbol(T, Decl(inferTypes1.ts, 77, 15))
>T : Symbol(T, Decl(inferTypes1.ts, 90, 15))
>T : Symbol(T, Decl(inferTypes1.ts, 90, 15))
: T extends undefined | Function ? never // undefined and functions are removed
>T : Symbol(T, Decl(inferTypes1.ts, 77, 15))
>T : Symbol(T, Decl(inferTypes1.ts, 90, 15))
>Function : Symbol(Function, Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --))
: T extends { toJSON(): infer R } ? R // toJSON is called if it exists (e.g. Date)
>T : Symbol(T, Decl(inferTypes1.ts, 77, 15))
>toJSON : Symbol(toJSON, Decl(inferTypes1.ts, 80, 17))
>R : Symbol(R, Decl(inferTypes1.ts, 80, 33))
>R : Symbol(R, Decl(inferTypes1.ts, 80, 33))
>T : Symbol(T, Decl(inferTypes1.ts, 90, 15))
>toJSON : Symbol(toJSON, Decl(inferTypes1.ts, 93, 17))
>R : Symbol(R, Decl(inferTypes1.ts, 93, 33))
>R : Symbol(R, Decl(inferTypes1.ts, 93, 33))
: T extends object ? JsonifiedObject<T>
>T : Symbol(T, Decl(inferTypes1.ts, 77, 15))
>JsonifiedObject : Symbol(JsonifiedObject, Decl(inferTypes1.ts, 71, 44))
>T : Symbol(T, Decl(inferTypes1.ts, 77, 15))
>T : Symbol(T, Decl(inferTypes1.ts, 90, 15))
>JsonifiedObject : Symbol(JsonifiedObject, Decl(inferTypes1.ts, 84, 66))
>T : Symbol(T, Decl(inferTypes1.ts, 90, 15))
: "what is this";
type Example = {
>Example : Symbol(Example, Decl(inferTypes1.ts, 82, 21))
>Example : Symbol(Example, Decl(inferTypes1.ts, 95, 21))
str: "literalstring",
>str : Symbol(str, Decl(inferTypes1.ts, 84, 16))
>str : Symbol(str, Decl(inferTypes1.ts, 97, 16))
fn: () => void,
>fn : Symbol(fn, Decl(inferTypes1.ts, 85, 25))
>fn : Symbol(fn, Decl(inferTypes1.ts, 98, 25))
date: Date,
>date : Symbol(date, Decl(inferTypes1.ts, 86, 19))
>date : Symbol(date, Decl(inferTypes1.ts, 99, 19))
>Date : Symbol(Date, Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --))
customClass: MyClass,
>customClass : Symbol(customClass, Decl(inferTypes1.ts, 87, 15))
>MyClass : Symbol(MyClass, Decl(inferTypes1.ts, 94, 1))
>customClass : Symbol(customClass, Decl(inferTypes1.ts, 100, 15))
>MyClass : Symbol(MyClass, Decl(inferTypes1.ts, 107, 1))
obj: {
>obj : Symbol(obj, Decl(inferTypes1.ts, 88, 25))
>obj : Symbol(obj, Decl(inferTypes1.ts, 101, 25))
prop: "property",
>prop : Symbol(prop, Decl(inferTypes1.ts, 89, 10))
>prop : Symbol(prop, Decl(inferTypes1.ts, 102, 10))
clz: MyClass,
>clz : Symbol(clz, Decl(inferTypes1.ts, 90, 25))
>MyClass : Symbol(MyClass, Decl(inferTypes1.ts, 94, 1))
>clz : Symbol(clz, Decl(inferTypes1.ts, 103, 25))
>MyClass : Symbol(MyClass, Decl(inferTypes1.ts, 107, 1))
nested: { attr: Date }
>nested : Symbol(nested, Decl(inferTypes1.ts, 91, 21))
>attr : Symbol(attr, Decl(inferTypes1.ts, 92, 17))
>nested : Symbol(nested, Decl(inferTypes1.ts, 104, 21))
>attr : Symbol(attr, Decl(inferTypes1.ts, 105, 17))
>Date : Symbol(Date, Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --))
},
}
declare class MyClass {
>MyClass : Symbol(MyClass, Decl(inferTypes1.ts, 94, 1))
>MyClass : Symbol(MyClass, Decl(inferTypes1.ts, 107, 1))
toJSON(): "correct";
>toJSON : Symbol(MyClass.toJSON, Decl(inferTypes1.ts, 96, 23))
>toJSON : Symbol(MyClass.toJSON, Decl(inferTypes1.ts, 109, 23))
}
type JsonifiedExample = Jsonified<Example>;
>JsonifiedExample : Symbol(JsonifiedExample, Decl(inferTypes1.ts, 98, 1))
>Jsonified : Symbol(Jsonified, Decl(inferTypes1.ts, 75, 77))
>Example : Symbol(Example, Decl(inferTypes1.ts, 82, 21))
>JsonifiedExample : Symbol(JsonifiedExample, Decl(inferTypes1.ts, 111, 1))
>Jsonified : Symbol(Jsonified, Decl(inferTypes1.ts, 88, 77))
>Example : Symbol(Example, Decl(inferTypes1.ts, 95, 21))
declare let ex: JsonifiedExample;
>ex : Symbol(ex, Decl(inferTypes1.ts, 101, 11))
>JsonifiedExample : Symbol(JsonifiedExample, Decl(inferTypes1.ts, 98, 1))
>ex : Symbol(ex, Decl(inferTypes1.ts, 114, 11))
>JsonifiedExample : Symbol(JsonifiedExample, Decl(inferTypes1.ts, 111, 1))
const z1: "correct" = ex.customClass;
>z1 : Symbol(z1, Decl(inferTypes1.ts, 102, 5))
>ex.customClass : Symbol(customClass, Decl(inferTypes1.ts, 87, 15))
>ex : Symbol(ex, Decl(inferTypes1.ts, 101, 11))
>customClass : Symbol(customClass, Decl(inferTypes1.ts, 87, 15))
>z1 : Symbol(z1, Decl(inferTypes1.ts, 115, 5))
>ex.customClass : Symbol(customClass, Decl(inferTypes1.ts, 100, 15))
>ex : Symbol(ex, Decl(inferTypes1.ts, 114, 11))
>customClass : Symbol(customClass, Decl(inferTypes1.ts, 100, 15))
const z2: string = ex.obj.nested.attr;
>z2 : Symbol(z2, Decl(inferTypes1.ts, 103, 5))
>ex.obj.nested.attr : Symbol(attr, Decl(inferTypes1.ts, 92, 17))
>ex.obj.nested : Symbol(nested, Decl(inferTypes1.ts, 91, 21))
>ex.obj : Symbol(obj, Decl(inferTypes1.ts, 88, 25))
>ex : Symbol(ex, Decl(inferTypes1.ts, 101, 11))
>obj : Symbol(obj, Decl(inferTypes1.ts, 88, 25))
>nested : Symbol(nested, Decl(inferTypes1.ts, 91, 21))
>attr : Symbol(attr, Decl(inferTypes1.ts, 92, 17))
>z2 : Symbol(z2, Decl(inferTypes1.ts, 116, 5))
>ex.obj.nested.attr : Symbol(attr, Decl(inferTypes1.ts, 105, 17))
>ex.obj.nested : Symbol(nested, Decl(inferTypes1.ts, 104, 21))
>ex.obj : Symbol(obj, Decl(inferTypes1.ts, 101, 25))
>ex : Symbol(ex, Decl(inferTypes1.ts, 114, 11))
>obj : Symbol(obj, Decl(inferTypes1.ts, 101, 25))
>nested : Symbol(nested, Decl(inferTypes1.ts, 104, 21))
>attr : Symbol(attr, Decl(inferTypes1.ts, 105, 17))
// Repros from #21631
type A1<T, U extends A1<any, any>> = [T, U];
>A1 : Symbol(A1, Decl(inferTypes1.ts, 116, 38))
>T : Symbol(T, Decl(inferTypes1.ts, 120, 8))
>U : Symbol(U, Decl(inferTypes1.ts, 120, 10))
>A1 : Symbol(A1, Decl(inferTypes1.ts, 116, 38))
>T : Symbol(T, Decl(inferTypes1.ts, 120, 8))
>U : Symbol(U, Decl(inferTypes1.ts, 120, 10))
type B1<S> = S extends A1<infer T, infer U> ? [T, U] : never;
>B1 : Symbol(B1, Decl(inferTypes1.ts, 120, 44))
>S : Symbol(S, Decl(inferTypes1.ts, 121, 8))
>S : Symbol(S, Decl(inferTypes1.ts, 121, 8))
>A1 : Symbol(A1, Decl(inferTypes1.ts, 116, 38))
>T : Symbol(T, Decl(inferTypes1.ts, 121, 31))
>U : Symbol(U, Decl(inferTypes1.ts, 121, 40))
>T : Symbol(T, Decl(inferTypes1.ts, 121, 31))
>U : Symbol(U, Decl(inferTypes1.ts, 121, 40))
type A2<T, U extends void> = [T, U];
>A2 : Symbol(A2, Decl(inferTypes1.ts, 121, 61))
>T : Symbol(T, Decl(inferTypes1.ts, 123, 8))
>U : Symbol(U, Decl(inferTypes1.ts, 123, 10))
>T : Symbol(T, Decl(inferTypes1.ts, 123, 8))
>U : Symbol(U, Decl(inferTypes1.ts, 123, 10))
type B2<S> = S extends A2<infer T, infer U> ? [T, U] : never;
>B2 : Symbol(B2, Decl(inferTypes1.ts, 123, 36))
>S : Symbol(S, Decl(inferTypes1.ts, 124, 8))
>S : Symbol(S, Decl(inferTypes1.ts, 124, 8))
>A2 : Symbol(A2, Decl(inferTypes1.ts, 121, 61))
>T : Symbol(T, Decl(inferTypes1.ts, 124, 31))
>U : Symbol(U, Decl(inferTypes1.ts, 124, 40))
>T : Symbol(T, Decl(inferTypes1.ts, 124, 31))
>U : Symbol(U, Decl(inferTypes1.ts, 124, 40))
type C2<S, U extends void> = S extends A2<infer T, U> ? [T, U] : never;
>C2 : Symbol(C2, Decl(inferTypes1.ts, 124, 61))
>S : Symbol(S, Decl(inferTypes1.ts, 125, 8))
>U : Symbol(U, Decl(inferTypes1.ts, 125, 10))
>S : Symbol(S, Decl(inferTypes1.ts, 125, 8))
>A2 : Symbol(A2, Decl(inferTypes1.ts, 121, 61))
>T : Symbol(T, Decl(inferTypes1.ts, 125, 47))
>U : Symbol(U, Decl(inferTypes1.ts, 125, 10))
>T : Symbol(T, Decl(inferTypes1.ts, 125, 47))
>U : Symbol(U, Decl(inferTypes1.ts, 125, 10))
+133
View File
@@ -321,6 +321,91 @@ type T62<T> = U extends (infer U)[] ? U : U; // Error
>U : U
>U : No type information available!
type T70<T extends string> = { x: T };
>T70 : T70<T>
>T : T
>x : T
>T : T
type T71<T> = T extends T70<infer U> ? T70<U> : never;
>T71 : T71<T>
>T : T
>T : T
>T70 : T70<T>
>U : U
>T70 : T70<T>
>U : U
type T72<T extends number> = { y: T };
>T72 : T72<T>
>T : T
>y : T
>T : T
type T73<T> = T extends T72<infer U> ? T70<U> : never; // Error
>T73 : T73<T>
>T : T
>T : T
>T72 : T72<T>
>U : U
>T70 : T70<T>
>U : U
type T74<T extends number, U extends string> = { x: T, y: U };
>T74 : T74<T, U>
>T : T
>U : U
>x : T
>T : T
>y : U
>U : U
type T75<T> = T extends T74<infer U, infer U> ? T70<U> | T72<U> | T74<U, U> : never;
>T75 : T75<T>
>T : T
>T : T
>T74 : T74<T, U>
>U : U
>U : U
>T70 : T70<T>
>U : U
>T72 : T72<T>
>U : U
>T74 : T74<T, U>
>U : U
>U : U
type T76<T extends T[], U extends T> = { x: T };
>T76 : T76<T, U>
>T : T
>T : T
>U : U
>T : T
>x : T
>T : T
type T77<T> = T extends T76<infer X, infer Y> ? T76<X, Y> : never;
>T77 : T77<T>
>T : T
>T : T
>T76 : T76<T, U>
>X : X
>Y : Y
>T76 : T76<T, U>
>X : X
>Y : Y
type T78<T> = T extends T76<infer X, infer X> ? T76<X, X> : never;
>T78 : T78<T>
>T : T
>T : T
>T76 : T76<T, U>
>X : X
>X : X
>T76 : T76<T, U>
>X : X
>X : X
// Example from #21496
type JsonifiedObject<T extends object> = { [K in keyof T]: Jsonified<T[K]> };
@@ -425,3 +510,51 @@ const z2: string = ex.obj.nested.attr;
>nested : JsonifiedObject<{ attr: Date; }>
>attr : string
// Repros from #21631
type A1<T, U extends A1<any, any>> = [T, U];
>A1 : [T, U]
>T : T
>U : U
>A1 : [T, U]
>T : T
>U : U
type B1<S> = S extends A1<infer T, infer U> ? [T, U] : never;
>B1 : B1<S>
>S : S
>S : S
>A1 : [T, U]
>T : T
>U : U
>T : T
>U : U
type A2<T, U extends void> = [T, U];
>A2 : [T, U]
>T : T
>U : U
>T : T
>U : U
type B2<S> = S extends A2<infer T, infer U> ? [T, U] : never;
>B2 : B2<S>
>S : S
>S : S
>A2 : [T, U]
>T : T
>U : U
>T : T
>U : U
type C2<S, U extends void> = S extends A2<infer T, U> ? [T, U] : never;
>C2 : C2<S, U>
>S : S
>U : U
>S : S
>A2 : [T, U]
>T : T
>U : U
>T : T
>U : U
@@ -1,10 +1,10 @@
tests/cases/compiler/index.js(2,19): error TS2315: Type 'boolean' is not generic.
tests/cases/compiler/index2.js(2,19): error TS2315: Type 'void' is not generic.
tests/cases/compiler/index3.js(2,19): error TS2315: Type 'undefined' is not generic.
tests/cases/compiler/index.js(2,19): error TS2315: Type 'Boolean' is not generic.
tests/cases/compiler/index2.js(2,19): error TS2315: Type 'Void' is not generic.
tests/cases/compiler/index3.js(2,19): error TS2315: Type 'Undefined' is not generic.
tests/cases/compiler/index4.js(2,19): error TS2315: Type 'Function' is not generic.
tests/cases/compiler/index5.js(2,19): error TS2315: Type 'string' is not generic.
tests/cases/compiler/index6.js(2,19): error TS2315: Type 'number' is not generic.
tests/cases/compiler/index7.js(2,19): error TS2315: Type 'any' is not generic.
tests/cases/compiler/index5.js(2,19): error TS2315: Type 'String' is not generic.
tests/cases/compiler/index6.js(2,19): error TS2315: Type 'Number' is not generic.
tests/cases/compiler/index7.js(2,19): error TS2315: Type 'Object' is not generic.
tests/cases/compiler/index8.js(4,12): error TS2304: Cannot find name 'fn'.
tests/cases/compiler/index8.js(4,15): error TS2304: Cannot find name 'T'.
@@ -13,7 +13,7 @@ tests/cases/compiler/index8.js(4,15): error TS2304: Cannot find name 'T'.
/**
* @param {<T>(m: Boolean<T>) => string} somebody
~~~~~~~~~~
!!! error TS2315: Type 'boolean' is not generic.
!!! error TS2315: Type 'Boolean' is not generic.
*/
function sayHello(somebody) {
return 'Hello ' + somebody;
@@ -23,7 +23,7 @@ tests/cases/compiler/index8.js(4,15): error TS2304: Cannot find name 'T'.
/**
* @param {<T>(m: Void<T>) => string} somebody
~~~~~~~
!!! error TS2315: Type 'void' is not generic.
!!! error TS2315: Type 'Void' is not generic.
*/
function sayHello2(somebody) {
return 'Hello ' + somebody;
@@ -34,7 +34,7 @@ tests/cases/compiler/index8.js(4,15): error TS2304: Cannot find name 'T'.
/**
* @param {<T>(m: Undefined<T>) => string} somebody
~~~~~~~~~~~~
!!! error TS2315: Type 'undefined' is not generic.
!!! error TS2315: Type 'Undefined' is not generic.
*/
function sayHello3(somebody) {
return 'Hello ' + somebody;
@@ -56,7 +56,7 @@ tests/cases/compiler/index8.js(4,15): error TS2304: Cannot find name 'T'.
/**
* @param {<T>(m: String<T>) => string} somebody
~~~~~~~~~
!!! error TS2315: Type 'string' is not generic.
!!! error TS2315: Type 'String' is not generic.
*/
function sayHello5(somebody) {
return 'Hello ' + somebody;
@@ -67,7 +67,7 @@ tests/cases/compiler/index8.js(4,15): error TS2304: Cannot find name 'T'.
/**
* @param {<T>(m: Number<T>) => string} somebody
~~~~~~~~~
!!! error TS2315: Type 'number' is not generic.
!!! error TS2315: Type 'Number' is not generic.
*/
function sayHello6(somebody) {
return 'Hello ' + somebody;
@@ -78,7 +78,7 @@ tests/cases/compiler/index8.js(4,15): error TS2304: Cannot find name 'T'.
/**
* @param {<T>(m: Object<T>) => string} somebody
~~~~~~~~~
!!! error TS2315: Type 'any' is not generic.
!!! error TS2315: Type 'Object' is not generic.
*/
function sayHello7(somebody) {
return 'Hello ' + somebody;
@@ -74,6 +74,19 @@ type T60 = infer U; // Error
type T61<T> = infer A extends infer B ? infer C : infer D; // Error
type T62<T> = U extends (infer U)[] ? U : U; // Error
type T70<T extends string> = { x: T };
type T71<T> = T extends T70<infer U> ? T70<U> : never;
type T72<T extends number> = { y: T };
type T73<T> = T extends T72<infer U> ? T70<U> : never; // Error
type T74<T extends number, U extends string> = { x: T, y: U };
type T75<T> = T extends T74<infer U, infer U> ? T70<U> | T72<U> | T74<U, U> : never;
type T76<T extends T[], U extends T> = { x: T };
type T77<T> = T extends T76<infer X, infer Y> ? T76<X, Y> : never;
type T78<T> = T extends T76<infer X, infer X> ? T76<X, X> : never;
// Example from #21496
type JsonifiedObject<T extends object> = { [K in keyof T]: Jsonified<T[K]> };
@@ -105,3 +118,12 @@ type JsonifiedExample = Jsonified<Example>;
declare let ex: JsonifiedExample;
const z1: "correct" = ex.customClass;
const z2: string = ex.obj.nested.attr;
// Repros from #21631
type A1<T, U extends A1<any, any>> = [T, U];
type B1<S> = S extends A1<infer T, infer U> ? [T, U] : never;
type A2<T, U extends void> = [T, U];
type B2<S> = S extends A2<infer T, infer U> ? [T, U] : never;
type C2<S, U extends void> = S extends A2<infer T, U> ? [T, U] : never;