Merge pull request #12623 from Microsoft/nestedIndexedAccess
Treat indexed access types 'T[K]' as type variables
This commit is contained in:
commit
a230cb7e77
|
@ -4513,10 +4513,10 @@ namespace ts {
|
|||
setStructuredTypeMembers(type, emptySymbols, emptyArray, emptyArray, undefined, undefined);
|
||||
// In { [P in K]: T }, we refer to P as the type parameter type, K as the constraint type,
|
||||
// and T as the template type. If K is of the form 'keyof S', the mapped type and S are
|
||||
// isomorphic and we copy property modifiers from corresponding properties in S.
|
||||
// homomorphic and we copy property modifiers from corresponding properties in S.
|
||||
const typeParameter = getTypeParameterFromMappedType(type);
|
||||
const constraintType = getConstraintTypeFromMappedType(type);
|
||||
const isomorphicType = getIsomorphicTypeFromMappedType(type);
|
||||
const homomorphicType = getHomomorphicTypeFromMappedType(type);
|
||||
const templateType = getTemplateTypeFromMappedType(type);
|
||||
const templateReadonly = !!type.declaration.readonlyToken;
|
||||
const templateOptional = !!type.declaration.questionToken;
|
||||
|
@ -4536,11 +4536,11 @@ namespace ts {
|
|||
// Otherwise, for type string create a string index signature.
|
||||
if (t.flags & TypeFlags.StringLiteral) {
|
||||
const propName = (<LiteralType>t).text;
|
||||
const isomorphicProp = isomorphicType && getPropertyOfType(isomorphicType, propName);
|
||||
const isOptional = templateOptional || !!(isomorphicProp && isomorphicProp.flags & SymbolFlags.Optional);
|
||||
const homomorphicProp = homomorphicType && getPropertyOfType(homomorphicType, propName);
|
||||
const isOptional = templateOptional || !!(homomorphicProp && homomorphicProp.flags & SymbolFlags.Optional);
|
||||
const prop = <TransientSymbol>createSymbol(SymbolFlags.Property | SymbolFlags.Transient | (isOptional ? SymbolFlags.Optional : 0), propName);
|
||||
prop.type = propType;
|
||||
prop.isReadonly = templateReadonly || isomorphicProp && isReadonlySymbol(isomorphicProp);
|
||||
prop.isReadonly = templateReadonly || homomorphicProp && isReadonlySymbol(homomorphicProp);
|
||||
members[propName] = prop;
|
||||
}
|
||||
else if (t.flags & TypeFlags.String) {
|
||||
|
@ -4567,7 +4567,7 @@ namespace ts {
|
|||
unknownType);
|
||||
}
|
||||
|
||||
function getIsomorphicTypeFromMappedType(type: MappedType) {
|
||||
function getHomomorphicTypeFromMappedType(type: MappedType) {
|
||||
const constraint = getConstraintDeclaration(getTypeParameterFromMappedType(type));
|
||||
return constraint.kind === SyntaxKind.TypeOperator ? instantiateType(getTypeFromTypeNode((<TypeOperatorNode>constraint).type), type.mapper || identityMapper) : undefined;
|
||||
}
|
||||
|
@ -5912,7 +5912,7 @@ namespace ts {
|
|||
return links.resolvedType;
|
||||
}
|
||||
|
||||
function getIndexTypeForTypeParameter(type: TypeParameter) {
|
||||
function getIndexTypeForTypeVariable(type: TypeVariable) {
|
||||
if (!type.resolvedIndexType) {
|
||||
type.resolvedIndexType = <IndexType>createType(TypeFlags.Index);
|
||||
type.resolvedIndexType.type = type;
|
||||
|
@ -5931,7 +5931,7 @@ namespace ts {
|
|||
}
|
||||
|
||||
function getIndexType(type: Type): Type {
|
||||
return type.flags & TypeFlags.TypeParameter ? getIndexTypeForTypeParameter(<TypeParameter>type) :
|
||||
return type.flags & TypeFlags.TypeVariable ? getIndexTypeForTypeVariable(<TypeVariable>type) :
|
||||
getObjectFlags(type) & ObjectFlags.Mapped ? getConstraintTypeFromMappedType(<MappedType>type) :
|
||||
type.flags & TypeFlags.Any || getIndexInfoOfType(type, IndexKind.String) ? stringType :
|
||||
getLiteralTypeFromPropertyNames(type);
|
||||
|
@ -6032,13 +6032,14 @@ namespace ts {
|
|||
}
|
||||
|
||||
function getIndexedAccessType(objectType: Type, indexType: Type, accessNode?: ElementAccessExpression | IndexedAccessTypeNode) {
|
||||
if (indexType.flags & TypeFlags.TypeParameter ||
|
||||
objectType.flags & TypeFlags.TypeParameter && indexType.flags & TypeFlags.Index ||
|
||||
if (indexType.flags & TypeFlags.TypeVariable ||
|
||||
objectType.flags & TypeFlags.TypeVariable && indexType.flags & TypeFlags.Index ||
|
||||
isGenericMappedType(objectType)) {
|
||||
// If either the object type or the index type are type parameters, or if the object type is a mapped
|
||||
// type with a generic constraint, we are performing a higher-order index access where we cannot
|
||||
// meaningfully access the properties of the object type. In those cases, we first check that the
|
||||
// index type is assignable to 'keyof T' for the object type.
|
||||
// If the object type is a type variable (a type parameter or another indexed access type), if the
|
||||
// index type is a type variable or an index type, or if the object type is a mapped type with a
|
||||
// generic constraint, we are performing a higher-order index access where we cannot meaningfully
|
||||
// access the properties of the object type. In those cases, we first check that the index type is
|
||||
// assignable to 'keyof T' for the object type.
|
||||
if (accessNode) {
|
||||
if (!isTypeAssignableTo(indexType, getIndexType(objectType))) {
|
||||
error(accessNode, Diagnostics.Type_0_cannot_be_used_to_index_type_1, typeToString(indexType), typeToString(objectType));
|
||||
|
@ -6531,19 +6532,19 @@ namespace ts {
|
|||
}
|
||||
|
||||
function instantiateMappedType(type: MappedType, mapper: TypeMapper): Type {
|
||||
// Check if we have an isomorphic mapped type, i.e. a type of the form { [P in keyof T]: X } for some
|
||||
// type parameter T. If so, the mapped type is distributive over a union type and when T is instantiated
|
||||
// Check if we have a homomorphic mapped type, i.e. a type of the form { [P in keyof T]: X } for some
|
||||
// type variable T. If so, the mapped type is distributive over a union type and when T is instantiated
|
||||
// to a union type A | B, we produce { [P in keyof A]: X } | { [P in keyof B]: X }. Furthermore, for
|
||||
// isomorphic mapped types we leave primitive types alone. For example, when T is instantiated to a
|
||||
// homomorphic mapped types we leave primitive types alone. For example, when T is instantiated to a
|
||||
// union type A | undefined, we produce { [P in keyof A]: X } | undefined.
|
||||
const constraintType = getConstraintTypeFromMappedType(type);
|
||||
if (constraintType.flags & TypeFlags.Index) {
|
||||
const typeParameter = (<IndexType>constraintType).type;
|
||||
const mappedTypeParameter = mapper(typeParameter);
|
||||
if (typeParameter !== mappedTypeParameter) {
|
||||
return mapType(mappedTypeParameter, t => {
|
||||
const typeVariable = <TypeParameter>(<IndexType>constraintType).type;
|
||||
const mappedTypeVariable = instantiateType(typeVariable, mapper);
|
||||
if (typeVariable !== mappedTypeVariable) {
|
||||
return mapType(mappedTypeVariable, t => {
|
||||
if (isMappableType(t)) {
|
||||
const replacementMapper = createUnaryTypeMapper(typeParameter, t);
|
||||
const replacementMapper = createUnaryTypeMapper(typeVariable, t);
|
||||
const combinedMapper = mapper.mappedTypes && mapper.mappedTypes.length === 1 ? replacementMapper : combineTypeMappers(replacementMapper, mapper);
|
||||
combinedMapper.mappedTypes = mapper.mappedTypes;
|
||||
return instantiateMappedObjectType(type, combinedMapper);
|
||||
|
@ -7274,10 +7275,12 @@ namespace ts {
|
|||
}
|
||||
// Given a type parameter T with a constraint C, a type S is assignable to
|
||||
// keyof T if S is assignable to keyof C.
|
||||
const constraint = getConstraintOfTypeParameter((<IndexType>target).type);
|
||||
if (constraint) {
|
||||
if (result = isRelatedTo(source, getIndexType(constraint), reportErrors)) {
|
||||
return result;
|
||||
if ((<IndexType>target).type.flags & TypeFlags.TypeParameter) {
|
||||
const constraint = getConstraintOfTypeParameter(<TypeParameter>(<IndexType>target).type);
|
||||
if (constraint) {
|
||||
if (result = isRelatedTo(source, getIndexType(constraint), reportErrors)) {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -8458,69 +8461,68 @@ namespace ts {
|
|||
// Return true if the given type could possibly reference a type parameter for which
|
||||
// we perform type inference (i.e. a type parameter of a generic function). We cache
|
||||
// results for union and intersection types for performance reasons.
|
||||
function couldContainTypeParameters(type: Type): boolean {
|
||||
function couldContainTypeVariables(type: Type): boolean {
|
||||
const objectFlags = getObjectFlags(type);
|
||||
return !!(type.flags & (TypeFlags.TypeParameter | TypeFlags.IndexedAccess) ||
|
||||
objectFlags & ObjectFlags.Reference && forEach((<TypeReference>type).typeArguments, couldContainTypeParameters) ||
|
||||
return !!(type.flags & TypeFlags.TypeVariable ||
|
||||
objectFlags & ObjectFlags.Reference && forEach((<TypeReference>type).typeArguments, couldContainTypeVariables) ||
|
||||
objectFlags & ObjectFlags.Anonymous && type.symbol && type.symbol.flags & (SymbolFlags.Method | SymbolFlags.TypeLiteral | SymbolFlags.Class) ||
|
||||
objectFlags & ObjectFlags.Mapped ||
|
||||
type.flags & TypeFlags.UnionOrIntersection && couldUnionOrIntersectionContainTypeParameters(<UnionOrIntersectionType>type));
|
||||
type.flags & TypeFlags.UnionOrIntersection && couldUnionOrIntersectionContainTypeVariables(<UnionOrIntersectionType>type));
|
||||
}
|
||||
|
||||
function couldUnionOrIntersectionContainTypeParameters(type: UnionOrIntersectionType): boolean {
|
||||
if (type.couldContainTypeParameters === undefined) {
|
||||
type.couldContainTypeParameters = forEach(type.types, couldContainTypeParameters);
|
||||
function couldUnionOrIntersectionContainTypeVariables(type: UnionOrIntersectionType): boolean {
|
||||
if (type.couldContainTypeVariables === undefined) {
|
||||
type.couldContainTypeVariables = forEach(type.types, couldContainTypeVariables);
|
||||
}
|
||||
return type.couldContainTypeParameters;
|
||||
return type.couldContainTypeVariables;
|
||||
}
|
||||
|
||||
function isTypeParameterAtTopLevel(type: Type, typeParameter: TypeParameter): boolean {
|
||||
return type === typeParameter || type.flags & TypeFlags.UnionOrIntersection && forEach((<UnionOrIntersectionType>type).types, t => isTypeParameterAtTopLevel(t, typeParameter));
|
||||
}
|
||||
|
||||
// Infer a suitable input type for an isomorphic mapped type { [P in keyof T]: X }. We construct
|
||||
// Infer a suitable input type for a homomorphic mapped type { [P in keyof T]: X }. We construct
|
||||
// an object type with the same set of properties as the source type, where the type of each
|
||||
// property is computed by inferring from the source property type to X for a synthetic type
|
||||
// parameter T[P] (i.e. we treat the type T[P] as the type parameter we're inferring for).
|
||||
function inferTypeForIsomorphicMappedType(source: Type, target: MappedType): Type {
|
||||
if (!isMappableType(source)) {
|
||||
return source;
|
||||
// property is computed by inferring from the source property type to X for the type
|
||||
// variable T[P] (i.e. we treat the type T[P] as the type variable we're inferring for).
|
||||
function inferTypeForHomomorphicMappedType(source: Type, target: MappedType): Type {
|
||||
const properties = getPropertiesOfType(source);
|
||||
let indexInfo = getIndexInfoOfType(source, IndexKind.String);
|
||||
if (properties.length === 0 && !indexInfo) {
|
||||
return undefined;
|
||||
}
|
||||
const typeParameter = getIndexedAccessType((<IndexType>getConstraintTypeFromMappedType(target)).type, getTypeParameterFromMappedType(target));
|
||||
const typeParameterArray = [typeParameter];
|
||||
const typeVariable = <TypeVariable>getIndexedAccessType((<IndexType>getConstraintTypeFromMappedType(target)).type, getTypeParameterFromMappedType(target));
|
||||
const typeVariableArray = [typeVariable];
|
||||
const typeInferences = createTypeInferencesObject();
|
||||
const typeInferencesArray = [typeInferences];
|
||||
const templateType = getTemplateTypeFromMappedType(target);
|
||||
const readonlyMask = target.declaration.readonlyToken ? false : true;
|
||||
const optionalMask = target.declaration.questionToken ? 0 : SymbolFlags.Optional;
|
||||
const properties = getPropertiesOfType(source);
|
||||
const members = createSymbolTable(properties);
|
||||
let hasInferredTypes = false;
|
||||
for (const prop of properties) {
|
||||
const inferredPropType = inferTargetType(getTypeOfSymbol(prop));
|
||||
if (inferredPropType) {
|
||||
const inferredProp = <TransientSymbol>createSymbol(SymbolFlags.Property | SymbolFlags.Transient | prop.flags & optionalMask, prop.name);
|
||||
inferredProp.declarations = prop.declarations;
|
||||
inferredProp.type = inferredPropType;
|
||||
inferredProp.isReadonly = readonlyMask && isReadonlySymbol(prop);
|
||||
members[prop.name] = inferredProp;
|
||||
hasInferredTypes = true;
|
||||
if (!inferredPropType) {
|
||||
return undefined;
|
||||
}
|
||||
const inferredProp = <TransientSymbol>createSymbol(SymbolFlags.Property | SymbolFlags.Transient | prop.flags & optionalMask, prop.name);
|
||||
inferredProp.declarations = prop.declarations;
|
||||
inferredProp.type = inferredPropType;
|
||||
inferredProp.isReadonly = readonlyMask && isReadonlySymbol(prop);
|
||||
members[prop.name] = inferredProp;
|
||||
}
|
||||
let indexInfo = getIndexInfoOfType(source, IndexKind.String);
|
||||
if (indexInfo) {
|
||||
const inferredIndexType = inferTargetType(indexInfo.type);
|
||||
if (inferredIndexType) {
|
||||
indexInfo = createIndexInfo(inferredIndexType, readonlyMask && indexInfo.isReadonly);
|
||||
hasInferredTypes = true;
|
||||
if (!inferredIndexType) {
|
||||
return undefined;
|
||||
}
|
||||
indexInfo = createIndexInfo(inferredIndexType, readonlyMask && indexInfo.isReadonly);
|
||||
}
|
||||
return hasInferredTypes ? createAnonymousType(undefined, members, emptyArray, emptyArray, indexInfo, undefined) : source;
|
||||
return createAnonymousType(undefined, members, emptyArray, emptyArray, indexInfo, undefined);
|
||||
|
||||
function inferTargetType(sourceType: Type): Type {
|
||||
typeInferences.primary = undefined;
|
||||
typeInferences.secondary = undefined;
|
||||
inferTypes(typeParameterArray, typeInferencesArray, sourceType, templateType);
|
||||
inferTypes(typeVariableArray, typeInferencesArray, sourceType, templateType);
|
||||
const inferences = typeInferences.primary || typeInferences.secondary;
|
||||
return inferences && getUnionType(inferences, /*subtypeReduction*/ true);
|
||||
}
|
||||
|
@ -8530,7 +8532,7 @@ namespace ts {
|
|||
inferTypes(context.signature.typeParameters, context.inferences, originalSource, originalTarget);
|
||||
}
|
||||
|
||||
function inferTypes(typeParameters: Type[], typeInferences: TypeInferences[], originalSource: Type, originalTarget: Type) {
|
||||
function inferTypes(typeVariables: TypeVariable[], typeInferences: TypeInferences[], originalSource: Type, originalTarget: Type) {
|
||||
let sourceStack: Type[];
|
||||
let targetStack: Type[];
|
||||
let depth = 0;
|
||||
|
@ -8548,7 +8550,7 @@ namespace ts {
|
|||
}
|
||||
|
||||
function inferFromTypes(source: Type, target: Type) {
|
||||
if (!couldContainTypeParameters(target)) {
|
||||
if (!couldContainTypeVariables(target)) {
|
||||
return;
|
||||
}
|
||||
if (source.aliasSymbol && source.aliasTypeArguments && source.aliasSymbol === target.aliasSymbol) {
|
||||
|
@ -8598,7 +8600,7 @@ namespace ts {
|
|||
target = removeTypesFromUnionOrIntersection(<UnionOrIntersectionType>target, matchingTypes);
|
||||
}
|
||||
}
|
||||
if (target.flags & (TypeFlags.TypeParameter | TypeFlags.IndexedAccess)) {
|
||||
if (target.flags & TypeFlags.TypeVariable) {
|
||||
// If target is a type parameter, make an inference, unless the source type contains
|
||||
// the anyFunctionType (the wildcard type that's used to avoid contextually typing functions).
|
||||
// Because the anyFunctionType is internal, it should not be exposed to the user by adding
|
||||
|
@ -8608,8 +8610,8 @@ namespace ts {
|
|||
if (source.flags & TypeFlags.ContainsAnyFunctionType) {
|
||||
return;
|
||||
}
|
||||
for (let i = 0; i < typeParameters.length; i++) {
|
||||
if (target === typeParameters[i]) {
|
||||
for (let i = 0; i < typeVariables.length; i++) {
|
||||
if (target === typeVariables[i]) {
|
||||
const inferences = typeInferences[i];
|
||||
if (!inferences.isFixed) {
|
||||
// Any inferences that are made to a type parameter in a union type are inferior
|
||||
|
@ -8643,24 +8645,24 @@ namespace ts {
|
|||
}
|
||||
else if (target.flags & TypeFlags.UnionOrIntersection) {
|
||||
const targetTypes = (<UnionOrIntersectionType>target).types;
|
||||
let typeParameterCount = 0;
|
||||
let typeParameter: TypeParameter;
|
||||
// First infer to each type in union or intersection that isn't a type parameter
|
||||
let typeVariableCount = 0;
|
||||
let typeVariable: TypeVariable;
|
||||
// First infer to each type in union or intersection that isn't a type variable
|
||||
for (const t of targetTypes) {
|
||||
if (t.flags & TypeFlags.TypeParameter && contains(typeParameters, t)) {
|
||||
typeParameter = <TypeParameter>t;
|
||||
typeParameterCount++;
|
||||
if (t.flags & TypeFlags.TypeVariable && contains(typeVariables, t)) {
|
||||
typeVariable = <TypeVariable>t;
|
||||
typeVariableCount++;
|
||||
}
|
||||
else {
|
||||
inferFromTypes(source, t);
|
||||
}
|
||||
}
|
||||
// Next, if target containings a single naked type parameter, make a secondary inference to that type
|
||||
// parameter. This gives meaningful results for union types in co-variant positions and intersection
|
||||
// Next, if target containings a single naked type variable, make a secondary inference to that type
|
||||
// variable. This gives meaningful results for union types in co-variant positions and intersection
|
||||
// types in contra-variant positions (such as callback parameters).
|
||||
if (typeParameterCount === 1) {
|
||||
if (typeVariableCount === 1) {
|
||||
inferiority++;
|
||||
inferFromTypes(source, typeParameter);
|
||||
inferFromTypes(source, typeVariable);
|
||||
inferiority--;
|
||||
}
|
||||
}
|
||||
|
@ -8702,12 +8704,15 @@ namespace ts {
|
|||
if (getObjectFlags(target) & ObjectFlags.Mapped) {
|
||||
const constraintType = getConstraintTypeFromMappedType(<MappedType>target);
|
||||
if (constraintType.flags & TypeFlags.Index) {
|
||||
// We're inferring from some source type S to an isomorphic mapped type { [P in keyof T]: X },
|
||||
// where T is a type parameter. Use inferTypeForIsomorphicMappedType to infer a suitable source
|
||||
// We're inferring from some source type S to a homomorphic mapped type { [P in keyof T]: X },
|
||||
// where T is a type variable. Use inferTypeForHomomorphicMappedType to infer a suitable source
|
||||
// type and then infer from that type to T.
|
||||
const index = indexOf(typeParameters, (<IndexType>constraintType).type);
|
||||
const index = indexOf(typeVariables, (<IndexType>constraintType).type);
|
||||
if (index >= 0 && !typeInferences[index].isFixed) {
|
||||
inferFromTypes(inferTypeForIsomorphicMappedType(source, <MappedType>target), typeParameters[index]);
|
||||
const inferredType = inferTypeForHomomorphicMappedType(source, <MappedType>target);
|
||||
if (inferredType) {
|
||||
inferFromTypes(inferredType, typeVariables[index]);
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
@ -14388,7 +14393,7 @@ namespace ts {
|
|||
if (!(isTypeComparableTo(leftType, stringType) || isTypeOfKind(leftType, TypeFlags.NumberLike | TypeFlags.ESSymbol))) {
|
||||
error(left, Diagnostics.The_left_hand_side_of_an_in_expression_must_be_of_type_any_string_number_or_symbol);
|
||||
}
|
||||
if (!isTypeAnyOrAllConstituentTypesHaveKind(rightType, TypeFlags.Object | TypeFlags.TypeParameter | TypeFlags.IndexedAccess)) {
|
||||
if (!isTypeAnyOrAllConstituentTypesHaveKind(rightType, TypeFlags.Object | TypeFlags.TypeVariable)) {
|
||||
error(right, Diagnostics.The_right_hand_side_of_an_in_expression_must_be_of_type_any_an_object_type_or_a_type_parameter);
|
||||
}
|
||||
return booleanType;
|
||||
|
@ -17331,7 +17336,7 @@ namespace ts {
|
|||
|
||||
// unknownType is returned i.e. if node.expression is identifier whose name cannot be resolved
|
||||
// in this case error about missing name is already reported - do not report extra one
|
||||
if (!isTypeAnyOrAllConstituentTypesHaveKind(rightType, TypeFlags.Object | TypeFlags.TypeParameter | TypeFlags.IndexedAccess)) {
|
||||
if (!isTypeAnyOrAllConstituentTypesHaveKind(rightType, TypeFlags.Object | TypeFlags.TypeVariable)) {
|
||||
error(node.expression, Diagnostics.The_right_hand_side_of_a_for_in_statement_must_be_of_type_any_an_object_type_or_a_type_parameter);
|
||||
}
|
||||
|
||||
|
|
|
@ -2797,6 +2797,7 @@ namespace ts {
|
|||
UnionOrIntersection = Union | Intersection,
|
||||
StructuredType = Object | Union | Intersection,
|
||||
StructuredOrTypeParameter = StructuredType | TypeParameter | Index,
|
||||
TypeVariable = TypeParameter | IndexedAccess,
|
||||
|
||||
// 'Narrowable' types are types where narrowing actually narrows.
|
||||
// This *should* be every type other than null, undefined, void, and never
|
||||
|
@ -2907,7 +2908,7 @@ namespace ts {
|
|||
/* @internal */
|
||||
resolvedProperties: SymbolTable; // Cache of resolved properties
|
||||
/* @internal */
|
||||
couldContainTypeParameters: boolean;
|
||||
couldContainTypeVariables: boolean;
|
||||
}
|
||||
|
||||
export interface UnionType extends UnionOrIntersectionType { }
|
||||
|
@ -2963,8 +2964,13 @@ namespace ts {
|
|||
iteratorElementType?: Type;
|
||||
}
|
||||
|
||||
export interface TypeVariable extends Type {
|
||||
/* @internal */
|
||||
resolvedIndexType: IndexType;
|
||||
}
|
||||
|
||||
// Type parameters (TypeFlags.TypeParameter)
|
||||
export interface TypeParameter extends Type {
|
||||
export interface TypeParameter extends TypeVariable {
|
||||
constraint: Type; // Constraint
|
||||
/* @internal */
|
||||
target?: TypeParameter; // Instantiation target
|
||||
|
@ -2973,20 +2979,21 @@ namespace ts {
|
|||
/* @internal */
|
||||
resolvedApparentType: Type;
|
||||
/* @internal */
|
||||
resolvedIndexType: IndexType;
|
||||
/* @internal */
|
||||
isThisType?: boolean;
|
||||
}
|
||||
|
||||
export interface IndexType extends Type {
|
||||
type: TypeParameter;
|
||||
}
|
||||
|
||||
export interface IndexedAccessType extends Type {
|
||||
// Indexed access types (TypeFlags.IndexedAccess)
|
||||
// Possible forms are T[xxx], xxx[T], or xxx[keyof T], where T is a type variable
|
||||
export interface IndexedAccessType extends TypeVariable {
|
||||
objectType: Type;
|
||||
indexType: Type;
|
||||
}
|
||||
|
||||
// keyof T types (TypeFlags.Index)
|
||||
export interface IndexType extends Type {
|
||||
type: TypeVariable;
|
||||
}
|
||||
|
||||
export const enum SignatureKind {
|
||||
Call,
|
||||
Construct,
|
||||
|
|
|
@ -118,7 +118,32 @@ function f10(foo: Foo) {
|
|||
let x = validate(foo); // { a: number, readonly b: string }
|
||||
let y = clone(foo); // { a?: number, b: string }
|
||||
let z = validateAndClone(foo); // { a: number, b: string }
|
||||
}
|
||||
}
|
||||
|
||||
// Repro from #12606
|
||||
|
||||
type Func<T> = (...args: any[]) => T;
|
||||
type Spec<T> = {
|
||||
[P in keyof T]: Func<T[P]> | Spec<T[P]> ;
|
||||
};
|
||||
|
||||
/**
|
||||
* Given a spec object recursively mapping properties to functions, creates a function
|
||||
* producing an object of the same structure, by mapping each property to the result
|
||||
* of calling its associated function with the supplied arguments.
|
||||
*/
|
||||
declare function applySpec<T>(obj: Spec<T>): (...args: any[]) => T;
|
||||
|
||||
// Infers g1: (...args: any[]) => { sum: number, nested: { mul: string } }
|
||||
var g1 = applySpec({
|
||||
sum: (a: any) => 3,
|
||||
nested: {
|
||||
mul: (b: any) => "n"
|
||||
}
|
||||
});
|
||||
|
||||
// Infers g2: (...args: any[]) => { foo: { bar: { baz: boolean } } }
|
||||
var g2 = applySpec({ foo: { bar: { baz: (x: any) => true } } });
|
||||
|
||||
//// [isomorphicMappedTypeInference.js]
|
||||
function box(x) {
|
||||
|
@ -210,6 +235,15 @@ function f10(foo) {
|
|||
var y = clone(foo); // { a?: number, b: string }
|
||||
var z = validateAndClone(foo); // { a: number, b: string }
|
||||
}
|
||||
// Infers g1: (...args: any[]) => { sum: number, nested: { mul: string } }
|
||||
var g1 = applySpec({
|
||||
sum: function (a) { return 3; },
|
||||
nested: {
|
||||
mul: function (b) { return "n"; }
|
||||
}
|
||||
});
|
||||
// Infers g2: (...args: any[]) => { foo: { bar: { baz: boolean } } }
|
||||
var g2 = applySpec({ foo: { bar: { baz: function (x) { return true; } } } });
|
||||
|
||||
|
||||
//// [isomorphicMappedTypeInference.d.ts]
|
||||
|
@ -254,3 +288,26 @@ declare type Foo = {
|
|||
readonly b: string;
|
||||
};
|
||||
declare function f10(foo: Foo): void;
|
||||
declare type Func<T> = (...args: any[]) => T;
|
||||
declare type Spec<T> = {
|
||||
[P in keyof T]: Func<T[P]> | Spec<T[P]>;
|
||||
};
|
||||
/**
|
||||
* Given a spec object recursively mapping properties to functions, creates a function
|
||||
* producing an object of the same structure, by mapping each property to the result
|
||||
* of calling its associated function with the supplied arguments.
|
||||
*/
|
||||
declare function applySpec<T>(obj: Spec<T>): (...args: any[]) => T;
|
||||
declare var g1: (...args: any[]) => {
|
||||
sum: number;
|
||||
nested: {
|
||||
mul: string;
|
||||
};
|
||||
};
|
||||
declare var g2: (...args: any[]) => {
|
||||
foo: {
|
||||
bar: {
|
||||
baz: boolean;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
|
|
@ -393,3 +393,69 @@ function f10(foo: Foo) {
|
|||
>validateAndClone : Symbol(validateAndClone, Decl(isomorphicMappedTypeInference.ts, 107, 69))
|
||||
>foo : Symbol(foo, Decl(isomorphicMappedTypeInference.ts, 115, 13))
|
||||
}
|
||||
|
||||
// Repro from #12606
|
||||
|
||||
type Func<T> = (...args: any[]) => T;
|
||||
>Func : Symbol(Func, Decl(isomorphicMappedTypeInference.ts, 119, 1))
|
||||
>T : Symbol(T, Decl(isomorphicMappedTypeInference.ts, 123, 10))
|
||||
>args : Symbol(args, Decl(isomorphicMappedTypeInference.ts, 123, 16))
|
||||
>T : Symbol(T, Decl(isomorphicMappedTypeInference.ts, 123, 10))
|
||||
|
||||
type Spec<T> = {
|
||||
>Spec : Symbol(Spec, Decl(isomorphicMappedTypeInference.ts, 123, 37))
|
||||
>T : Symbol(T, Decl(isomorphicMappedTypeInference.ts, 124, 10))
|
||||
|
||||
[P in keyof T]: Func<T[P]> | Spec<T[P]> ;
|
||||
>P : Symbol(P, Decl(isomorphicMappedTypeInference.ts, 125, 5))
|
||||
>T : Symbol(T, Decl(isomorphicMappedTypeInference.ts, 124, 10))
|
||||
>Func : Symbol(Func, Decl(isomorphicMappedTypeInference.ts, 119, 1))
|
||||
>T : Symbol(T, Decl(isomorphicMappedTypeInference.ts, 124, 10))
|
||||
>P : Symbol(P, Decl(isomorphicMappedTypeInference.ts, 125, 5))
|
||||
>Spec : Symbol(Spec, Decl(isomorphicMappedTypeInference.ts, 123, 37))
|
||||
>T : Symbol(T, Decl(isomorphicMappedTypeInference.ts, 124, 10))
|
||||
>P : Symbol(P, Decl(isomorphicMappedTypeInference.ts, 125, 5))
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
* Given a spec object recursively mapping properties to functions, creates a function
|
||||
* producing an object of the same structure, by mapping each property to the result
|
||||
* of calling its associated function with the supplied arguments.
|
||||
*/
|
||||
declare function applySpec<T>(obj: Spec<T>): (...args: any[]) => T;
|
||||
>applySpec : Symbol(applySpec, Decl(isomorphicMappedTypeInference.ts, 126, 2))
|
||||
>T : Symbol(T, Decl(isomorphicMappedTypeInference.ts, 133, 27))
|
||||
>obj : Symbol(obj, Decl(isomorphicMappedTypeInference.ts, 133, 30))
|
||||
>Spec : Symbol(Spec, Decl(isomorphicMappedTypeInference.ts, 123, 37))
|
||||
>T : Symbol(T, Decl(isomorphicMappedTypeInference.ts, 133, 27))
|
||||
>args : Symbol(args, Decl(isomorphicMappedTypeInference.ts, 133, 46))
|
||||
>T : Symbol(T, Decl(isomorphicMappedTypeInference.ts, 133, 27))
|
||||
|
||||
// Infers g1: (...args: any[]) => { sum: number, nested: { mul: string } }
|
||||
var g1 = applySpec({
|
||||
>g1 : Symbol(g1, Decl(isomorphicMappedTypeInference.ts, 136, 3))
|
||||
>applySpec : Symbol(applySpec, Decl(isomorphicMappedTypeInference.ts, 126, 2))
|
||||
|
||||
sum: (a: any) => 3,
|
||||
>sum : Symbol(sum, Decl(isomorphicMappedTypeInference.ts, 136, 20))
|
||||
>a : Symbol(a, Decl(isomorphicMappedTypeInference.ts, 137, 10))
|
||||
|
||||
nested: {
|
||||
>nested : Symbol(nested, Decl(isomorphicMappedTypeInference.ts, 137, 23))
|
||||
|
||||
mul: (b: any) => "n"
|
||||
>mul : Symbol(mul, Decl(isomorphicMappedTypeInference.ts, 138, 13))
|
||||
>b : Symbol(b, Decl(isomorphicMappedTypeInference.ts, 139, 14))
|
||||
}
|
||||
});
|
||||
|
||||
// Infers g2: (...args: any[]) => { foo: { bar: { baz: boolean } } }
|
||||
var g2 = applySpec({ foo: { bar: { baz: (x: any) => true } } });
|
||||
>g2 : Symbol(g2, Decl(isomorphicMappedTypeInference.ts, 144, 3))
|
||||
>applySpec : Symbol(applySpec, Decl(isomorphicMappedTypeInference.ts, 126, 2))
|
||||
>foo : Symbol(foo, Decl(isomorphicMappedTypeInference.ts, 144, 20))
|
||||
>bar : Symbol(bar, Decl(isomorphicMappedTypeInference.ts, 144, 27))
|
||||
>baz : Symbol(baz, Decl(isomorphicMappedTypeInference.ts, 144, 34))
|
||||
>x : Symbol(x, Decl(isomorphicMappedTypeInference.ts, 144, 41))
|
||||
|
||||
|
|
|
@ -467,3 +467,82 @@ function f10(foo: Foo) {
|
|||
>validateAndClone : <T>(obj: { readonly [P in keyof T]?: T[P] | undefined; }) => T
|
||||
>foo : Foo
|
||||
}
|
||||
|
||||
// Repro from #12606
|
||||
|
||||
type Func<T> = (...args: any[]) => T;
|
||||
>Func : Func<T>
|
||||
>T : T
|
||||
>args : any[]
|
||||
>T : T
|
||||
|
||||
type Spec<T> = {
|
||||
>Spec : Spec<T>
|
||||
>T : T
|
||||
|
||||
[P in keyof T]: Func<T[P]> | Spec<T[P]> ;
|
||||
>P : P
|
||||
>T : T
|
||||
>Func : Func<T>
|
||||
>T : T
|
||||
>P : P
|
||||
>Spec : Spec<T>
|
||||
>T : T
|
||||
>P : P
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
* Given a spec object recursively mapping properties to functions, creates a function
|
||||
* producing an object of the same structure, by mapping each property to the result
|
||||
* of calling its associated function with the supplied arguments.
|
||||
*/
|
||||
declare function applySpec<T>(obj: Spec<T>): (...args: any[]) => T;
|
||||
>applySpec : <T>(obj: Spec<T>) => (...args: any[]) => T
|
||||
>T : T
|
||||
>obj : Spec<T>
|
||||
>Spec : Spec<T>
|
||||
>T : T
|
||||
>args : any[]
|
||||
>T : T
|
||||
|
||||
// Infers g1: (...args: any[]) => { sum: number, nested: { mul: string } }
|
||||
var g1 = applySpec({
|
||||
>g1 : (...args: any[]) => { sum: number; nested: { mul: string; }; }
|
||||
>applySpec({ sum: (a: any) => 3, nested: { mul: (b: any) => "n" }}) : (...args: any[]) => { sum: number; nested: { mul: string; }; }
|
||||
>applySpec : <T>(obj: Spec<T>) => (...args: any[]) => T
|
||||
>{ sum: (a: any) => 3, nested: { mul: (b: any) => "n" }} : { sum: (a: any) => number; nested: { mul: (b: any) => string; }; }
|
||||
|
||||
sum: (a: any) => 3,
|
||||
>sum : (a: any) => number
|
||||
>(a: any) => 3 : (a: any) => number
|
||||
>a : any
|
||||
>3 : 3
|
||||
|
||||
nested: {
|
||||
>nested : { mul: (b: any) => string; }
|
||||
>{ mul: (b: any) => "n" } : { mul: (b: any) => string; }
|
||||
|
||||
mul: (b: any) => "n"
|
||||
>mul : (b: any) => string
|
||||
>(b: any) => "n" : (b: any) => string
|
||||
>b : any
|
||||
>"n" : "n"
|
||||
}
|
||||
});
|
||||
|
||||
// Infers g2: (...args: any[]) => { foo: { bar: { baz: boolean } } }
|
||||
var g2 = applySpec({ foo: { bar: { baz: (x: any) => true } } });
|
||||
>g2 : (...args: any[]) => { foo: { bar: { baz: boolean; }; }; }
|
||||
>applySpec({ foo: { bar: { baz: (x: any) => true } } }) : (...args: any[]) => { foo: { bar: { baz: boolean; }; }; }
|
||||
>applySpec : <T>(obj: Spec<T>) => (...args: any[]) => T
|
||||
>{ foo: { bar: { baz: (x: any) => true } } } : { foo: { bar: { baz: (x: any) => boolean; }; }; }
|
||||
>foo : { bar: { baz: (x: any) => boolean; }; }
|
||||
>{ bar: { baz: (x: any) => true } } : { bar: { baz: (x: any) => boolean; }; }
|
||||
>bar : { baz: (x: any) => boolean; }
|
||||
>{ baz: (x: any) => true } : { baz: (x: any) => boolean; }
|
||||
>baz : (x: any) => boolean
|
||||
>(x: any) => true : (x: any) => boolean
|
||||
>x : any
|
||||
>true : true
|
||||
|
||||
|
|
|
@ -250,7 +250,48 @@ class OtherPerson {
|
|||
return getProperty(this, "parts")
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Modified repro from #12544
|
||||
|
||||
function path<T, K1 extends keyof T>(obj: T, key1: K1): T[K1];
|
||||
function path<T, K1 extends keyof T, K2 extends keyof T[K1]>(obj: T, key1: K1, key2: K2): T[K1][K2];
|
||||
function path<T, K1 extends keyof T, K2 extends keyof T[K1], K3 extends keyof T[K1][K2]>(obj: T, key1: K1, key2: K2, key3: K3): T[K1][K2][K3];
|
||||
function path(obj: any, ...keys: (string | number)[]): any;
|
||||
function path(obj: any, ...keys: (string | number)[]): any {
|
||||
let result = obj;
|
||||
for (let k of keys) {
|
||||
result = result[k];
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
type Thing = {
|
||||
a: { x: number, y: string },
|
||||
b: boolean
|
||||
};
|
||||
|
||||
|
||||
function f1(thing: Thing) {
|
||||
let x1 = path(thing, 'a'); // { x: number, y: string }
|
||||
let x2 = path(thing, 'a', 'y'); // string
|
||||
let x3 = path(thing, 'b'); // boolean
|
||||
let x4 = path(thing, ...['a', 'x']); // any
|
||||
}
|
||||
|
||||
// Repro from comment in #12114
|
||||
|
||||
const assignTo2 = <T, K1 extends keyof T, K2 extends keyof T[K1]>(object: T, key1: K1, key2: K2) =>
|
||||
(value: T[K1][K2]) => object[key1][key2] = value;
|
||||
|
||||
// Modified repro from #12573
|
||||
|
||||
declare function one<T>(handler: (t: T) => void): T
|
||||
var empty = one(() => {}) // inferred as {}, expected
|
||||
|
||||
type Handlers<T> = { [K in keyof T]: (t: T[K]) => void }
|
||||
declare function on<T>(handlerHash: Handlers<T>): T
|
||||
var hashOfEmpty1 = on({ test: () => {} }); // {}
|
||||
var hashOfEmpty2 = on({ test: (x: boolean) => {} }); // { test: boolean }
|
||||
|
||||
//// [keyofAndIndexedAccess.js]
|
||||
var __extends = (this && this.__extends) || function (d, b) {
|
||||
|
@ -430,6 +471,31 @@ var OtherPerson = (function () {
|
|||
};
|
||||
return OtherPerson;
|
||||
}());
|
||||
function path(obj) {
|
||||
var keys = [];
|
||||
for (var _i = 1; _i < arguments.length; _i++) {
|
||||
keys[_i - 1] = arguments[_i];
|
||||
}
|
||||
var result = obj;
|
||||
for (var _a = 0, keys_1 = keys; _a < keys_1.length; _a++) {
|
||||
var k = keys_1[_a];
|
||||
result = result[k];
|
||||
}
|
||||
return result;
|
||||
}
|
||||
function f1(thing) {
|
||||
var x1 = path(thing, 'a'); // { x: number, y: string }
|
||||
var x2 = path(thing, 'a', 'y'); // string
|
||||
var x3 = path(thing, 'b'); // boolean
|
||||
var x4 = path.apply(void 0, [thing].concat(['a', 'x'])); // any
|
||||
}
|
||||
// Repro from comment in #12114
|
||||
var assignTo2 = function (object, key1, key2) {
|
||||
return function (value) { return object[key1][key2] = value; };
|
||||
};
|
||||
var empty = one(function () { }); // inferred as {}, expected
|
||||
var hashOfEmpty1 = on({ test: function () { } }); // {}
|
||||
var hashOfEmpty2 = on({ test: function (x) { } }); // { test: boolean }
|
||||
|
||||
|
||||
//// [keyofAndIndexedAccess.d.ts]
|
||||
|
@ -551,3 +617,26 @@ declare class OtherPerson {
|
|||
constructor(parts: number);
|
||||
getParts(): number;
|
||||
}
|
||||
declare function path<T, K1 extends keyof T>(obj: T, key1: K1): T[K1];
|
||||
declare function path<T, K1 extends keyof T, K2 extends keyof T[K1]>(obj: T, key1: K1, key2: K2): T[K1][K2];
|
||||
declare function path<T, K1 extends keyof T, K2 extends keyof T[K1], K3 extends keyof T[K1][K2]>(obj: T, key1: K1, key2: K2, key3: K3): T[K1][K2][K3];
|
||||
declare function path(obj: any, ...keys: (string | number)[]): any;
|
||||
declare type Thing = {
|
||||
a: {
|
||||
x: number;
|
||||
y: string;
|
||||
};
|
||||
b: boolean;
|
||||
};
|
||||
declare function f1(thing: Thing): void;
|
||||
declare const assignTo2: <T, K1 extends keyof T, K2 extends keyof T[K1]>(object: T, key1: K1, key2: K2) => (value: T[K1][K2]) => T[K1][K2];
|
||||
declare function one<T>(handler: (t: T) => void): T;
|
||||
declare var empty: {};
|
||||
declare type Handlers<T> = {
|
||||
[K in keyof T]: (t: T[K]) => void;
|
||||
};
|
||||
declare function on<T>(handlerHash: Handlers<T>): T;
|
||||
declare var hashOfEmpty1: {};
|
||||
declare var hashOfEmpty2: {
|
||||
test: boolean;
|
||||
};
|
||||
|
|
|
@ -848,3 +848,196 @@ class OtherPerson {
|
|||
}
|
||||
}
|
||||
|
||||
// Modified repro from #12544
|
||||
|
||||
function path<T, K1 extends keyof T>(obj: T, key1: K1): T[K1];
|
||||
>path : Symbol(path, Decl(keyofAndIndexedAccess.ts, 250, 1), Decl(keyofAndIndexedAccess.ts, 254, 62), Decl(keyofAndIndexedAccess.ts, 255, 100), Decl(keyofAndIndexedAccess.ts, 256, 142), Decl(keyofAndIndexedAccess.ts, 257, 59))
|
||||
>T : Symbol(T, Decl(keyofAndIndexedAccess.ts, 254, 14))
|
||||
>K1 : Symbol(K1, Decl(keyofAndIndexedAccess.ts, 254, 16))
|
||||
>T : Symbol(T, Decl(keyofAndIndexedAccess.ts, 254, 14))
|
||||
>obj : Symbol(obj, Decl(keyofAndIndexedAccess.ts, 254, 37))
|
||||
>T : Symbol(T, Decl(keyofAndIndexedAccess.ts, 254, 14))
|
||||
>key1 : Symbol(key1, Decl(keyofAndIndexedAccess.ts, 254, 44))
|
||||
>K1 : Symbol(K1, Decl(keyofAndIndexedAccess.ts, 254, 16))
|
||||
>T : Symbol(T, Decl(keyofAndIndexedAccess.ts, 254, 14))
|
||||
>K1 : Symbol(K1, Decl(keyofAndIndexedAccess.ts, 254, 16))
|
||||
|
||||
function path<T, K1 extends keyof T, K2 extends keyof T[K1]>(obj: T, key1: K1, key2: K2): T[K1][K2];
|
||||
>path : Symbol(path, Decl(keyofAndIndexedAccess.ts, 250, 1), Decl(keyofAndIndexedAccess.ts, 254, 62), Decl(keyofAndIndexedAccess.ts, 255, 100), Decl(keyofAndIndexedAccess.ts, 256, 142), Decl(keyofAndIndexedAccess.ts, 257, 59))
|
||||
>T : Symbol(T, Decl(keyofAndIndexedAccess.ts, 255, 14))
|
||||
>K1 : Symbol(K1, Decl(keyofAndIndexedAccess.ts, 255, 16))
|
||||
>T : Symbol(T, Decl(keyofAndIndexedAccess.ts, 255, 14))
|
||||
>K2 : Symbol(K2, Decl(keyofAndIndexedAccess.ts, 255, 36))
|
||||
>T : Symbol(T, Decl(keyofAndIndexedAccess.ts, 255, 14))
|
||||
>K1 : Symbol(K1, Decl(keyofAndIndexedAccess.ts, 255, 16))
|
||||
>obj : Symbol(obj, Decl(keyofAndIndexedAccess.ts, 255, 61))
|
||||
>T : Symbol(T, Decl(keyofAndIndexedAccess.ts, 255, 14))
|
||||
>key1 : Symbol(key1, Decl(keyofAndIndexedAccess.ts, 255, 68))
|
||||
>K1 : Symbol(K1, Decl(keyofAndIndexedAccess.ts, 255, 16))
|
||||
>key2 : Symbol(key2, Decl(keyofAndIndexedAccess.ts, 255, 78))
|
||||
>K2 : Symbol(K2, Decl(keyofAndIndexedAccess.ts, 255, 36))
|
||||
>T : Symbol(T, Decl(keyofAndIndexedAccess.ts, 255, 14))
|
||||
>K1 : Symbol(K1, Decl(keyofAndIndexedAccess.ts, 255, 16))
|
||||
>K2 : Symbol(K2, Decl(keyofAndIndexedAccess.ts, 255, 36))
|
||||
|
||||
function path<T, K1 extends keyof T, K2 extends keyof T[K1], K3 extends keyof T[K1][K2]>(obj: T, key1: K1, key2: K2, key3: K3): T[K1][K2][K3];
|
||||
>path : Symbol(path, Decl(keyofAndIndexedAccess.ts, 250, 1), Decl(keyofAndIndexedAccess.ts, 254, 62), Decl(keyofAndIndexedAccess.ts, 255, 100), Decl(keyofAndIndexedAccess.ts, 256, 142), Decl(keyofAndIndexedAccess.ts, 257, 59))
|
||||
>T : Symbol(T, Decl(keyofAndIndexedAccess.ts, 256, 14))
|
||||
>K1 : Symbol(K1, Decl(keyofAndIndexedAccess.ts, 256, 16))
|
||||
>T : Symbol(T, Decl(keyofAndIndexedAccess.ts, 256, 14))
|
||||
>K2 : Symbol(K2, Decl(keyofAndIndexedAccess.ts, 256, 36))
|
||||
>T : Symbol(T, Decl(keyofAndIndexedAccess.ts, 256, 14))
|
||||
>K1 : Symbol(K1, Decl(keyofAndIndexedAccess.ts, 256, 16))
|
||||
>K3 : Symbol(K3, Decl(keyofAndIndexedAccess.ts, 256, 60))
|
||||
>T : Symbol(T, Decl(keyofAndIndexedAccess.ts, 256, 14))
|
||||
>K1 : Symbol(K1, Decl(keyofAndIndexedAccess.ts, 256, 16))
|
||||
>K2 : Symbol(K2, Decl(keyofAndIndexedAccess.ts, 256, 36))
|
||||
>obj : Symbol(obj, Decl(keyofAndIndexedAccess.ts, 256, 89))
|
||||
>T : Symbol(T, Decl(keyofAndIndexedAccess.ts, 256, 14))
|
||||
>key1 : Symbol(key1, Decl(keyofAndIndexedAccess.ts, 256, 96))
|
||||
>K1 : Symbol(K1, Decl(keyofAndIndexedAccess.ts, 256, 16))
|
||||
>key2 : Symbol(key2, Decl(keyofAndIndexedAccess.ts, 256, 106))
|
||||
>K2 : Symbol(K2, Decl(keyofAndIndexedAccess.ts, 256, 36))
|
||||
>key3 : Symbol(key3, Decl(keyofAndIndexedAccess.ts, 256, 116))
|
||||
>K3 : Symbol(K3, Decl(keyofAndIndexedAccess.ts, 256, 60))
|
||||
>T : Symbol(T, Decl(keyofAndIndexedAccess.ts, 256, 14))
|
||||
>K1 : Symbol(K1, Decl(keyofAndIndexedAccess.ts, 256, 16))
|
||||
>K2 : Symbol(K2, Decl(keyofAndIndexedAccess.ts, 256, 36))
|
||||
>K3 : Symbol(K3, Decl(keyofAndIndexedAccess.ts, 256, 60))
|
||||
|
||||
function path(obj: any, ...keys: (string | number)[]): any;
|
||||
>path : Symbol(path, Decl(keyofAndIndexedAccess.ts, 250, 1), Decl(keyofAndIndexedAccess.ts, 254, 62), Decl(keyofAndIndexedAccess.ts, 255, 100), Decl(keyofAndIndexedAccess.ts, 256, 142), Decl(keyofAndIndexedAccess.ts, 257, 59))
|
||||
>obj : Symbol(obj, Decl(keyofAndIndexedAccess.ts, 257, 14))
|
||||
>keys : Symbol(keys, Decl(keyofAndIndexedAccess.ts, 257, 23))
|
||||
|
||||
function path(obj: any, ...keys: (string | number)[]): any {
|
||||
>path : Symbol(path, Decl(keyofAndIndexedAccess.ts, 250, 1), Decl(keyofAndIndexedAccess.ts, 254, 62), Decl(keyofAndIndexedAccess.ts, 255, 100), Decl(keyofAndIndexedAccess.ts, 256, 142), Decl(keyofAndIndexedAccess.ts, 257, 59))
|
||||
>obj : Symbol(obj, Decl(keyofAndIndexedAccess.ts, 258, 14))
|
||||
>keys : Symbol(keys, Decl(keyofAndIndexedAccess.ts, 258, 23))
|
||||
|
||||
let result = obj;
|
||||
>result : Symbol(result, Decl(keyofAndIndexedAccess.ts, 259, 7))
|
||||
>obj : Symbol(obj, Decl(keyofAndIndexedAccess.ts, 258, 14))
|
||||
|
||||
for (let k of keys) {
|
||||
>k : Symbol(k, Decl(keyofAndIndexedAccess.ts, 260, 12))
|
||||
>keys : Symbol(keys, Decl(keyofAndIndexedAccess.ts, 258, 23))
|
||||
|
||||
result = result[k];
|
||||
>result : Symbol(result, Decl(keyofAndIndexedAccess.ts, 259, 7))
|
||||
>result : Symbol(result, Decl(keyofAndIndexedAccess.ts, 259, 7))
|
||||
>k : Symbol(k, Decl(keyofAndIndexedAccess.ts, 260, 12))
|
||||
}
|
||||
return result;
|
||||
>result : Symbol(result, Decl(keyofAndIndexedAccess.ts, 259, 7))
|
||||
}
|
||||
|
||||
type Thing = {
|
||||
>Thing : Symbol(Thing, Decl(keyofAndIndexedAccess.ts, 264, 1))
|
||||
|
||||
a: { x: number, y: string },
|
||||
>a : Symbol(a, Decl(keyofAndIndexedAccess.ts, 266, 14))
|
||||
>x : Symbol(x, Decl(keyofAndIndexedAccess.ts, 267, 8))
|
||||
>y : Symbol(y, Decl(keyofAndIndexedAccess.ts, 267, 19))
|
||||
|
||||
b: boolean
|
||||
>b : Symbol(b, Decl(keyofAndIndexedAccess.ts, 267, 32))
|
||||
|
||||
};
|
||||
|
||||
|
||||
function f1(thing: Thing) {
|
||||
>f1 : Symbol(f1, Decl(keyofAndIndexedAccess.ts, 269, 2))
|
||||
>thing : Symbol(thing, Decl(keyofAndIndexedAccess.ts, 272, 12))
|
||||
>Thing : Symbol(Thing, Decl(keyofAndIndexedAccess.ts, 264, 1))
|
||||
|
||||
let x1 = path(thing, 'a'); // { x: number, y: string }
|
||||
>x1 : Symbol(x1, Decl(keyofAndIndexedAccess.ts, 273, 7))
|
||||
>path : Symbol(path, Decl(keyofAndIndexedAccess.ts, 250, 1), Decl(keyofAndIndexedAccess.ts, 254, 62), Decl(keyofAndIndexedAccess.ts, 255, 100), Decl(keyofAndIndexedAccess.ts, 256, 142), Decl(keyofAndIndexedAccess.ts, 257, 59))
|
||||
>thing : Symbol(thing, Decl(keyofAndIndexedAccess.ts, 272, 12))
|
||||
|
||||
let x2 = path(thing, 'a', 'y'); // string
|
||||
>x2 : Symbol(x2, Decl(keyofAndIndexedAccess.ts, 274, 7))
|
||||
>path : Symbol(path, Decl(keyofAndIndexedAccess.ts, 250, 1), Decl(keyofAndIndexedAccess.ts, 254, 62), Decl(keyofAndIndexedAccess.ts, 255, 100), Decl(keyofAndIndexedAccess.ts, 256, 142), Decl(keyofAndIndexedAccess.ts, 257, 59))
|
||||
>thing : Symbol(thing, Decl(keyofAndIndexedAccess.ts, 272, 12))
|
||||
|
||||
let x3 = path(thing, 'b'); // boolean
|
||||
>x3 : Symbol(x3, Decl(keyofAndIndexedAccess.ts, 275, 7))
|
||||
>path : Symbol(path, Decl(keyofAndIndexedAccess.ts, 250, 1), Decl(keyofAndIndexedAccess.ts, 254, 62), Decl(keyofAndIndexedAccess.ts, 255, 100), Decl(keyofAndIndexedAccess.ts, 256, 142), Decl(keyofAndIndexedAccess.ts, 257, 59))
|
||||
>thing : Symbol(thing, Decl(keyofAndIndexedAccess.ts, 272, 12))
|
||||
|
||||
let x4 = path(thing, ...['a', 'x']); // any
|
||||
>x4 : Symbol(x4, Decl(keyofAndIndexedAccess.ts, 276, 7))
|
||||
>path : Symbol(path, Decl(keyofAndIndexedAccess.ts, 250, 1), Decl(keyofAndIndexedAccess.ts, 254, 62), Decl(keyofAndIndexedAccess.ts, 255, 100), Decl(keyofAndIndexedAccess.ts, 256, 142), Decl(keyofAndIndexedAccess.ts, 257, 59))
|
||||
>thing : Symbol(thing, Decl(keyofAndIndexedAccess.ts, 272, 12))
|
||||
}
|
||||
|
||||
// Repro from comment in #12114
|
||||
|
||||
const assignTo2 = <T, K1 extends keyof T, K2 extends keyof T[K1]>(object: T, key1: K1, key2: K2) =>
|
||||
>assignTo2 : Symbol(assignTo2, Decl(keyofAndIndexedAccess.ts, 281, 5))
|
||||
>T : Symbol(T, Decl(keyofAndIndexedAccess.ts, 281, 19))
|
||||
>K1 : Symbol(K1, Decl(keyofAndIndexedAccess.ts, 281, 21))
|
||||
>T : Symbol(T, Decl(keyofAndIndexedAccess.ts, 281, 19))
|
||||
>K2 : Symbol(K2, Decl(keyofAndIndexedAccess.ts, 281, 41))
|
||||
>T : Symbol(T, Decl(keyofAndIndexedAccess.ts, 281, 19))
|
||||
>K1 : Symbol(K1, Decl(keyofAndIndexedAccess.ts, 281, 21))
|
||||
>object : Symbol(object, Decl(keyofAndIndexedAccess.ts, 281, 66))
|
||||
>T : Symbol(T, Decl(keyofAndIndexedAccess.ts, 281, 19))
|
||||
>key1 : Symbol(key1, Decl(keyofAndIndexedAccess.ts, 281, 76))
|
||||
>K1 : Symbol(K1, Decl(keyofAndIndexedAccess.ts, 281, 21))
|
||||
>key2 : Symbol(key2, Decl(keyofAndIndexedAccess.ts, 281, 86))
|
||||
>K2 : Symbol(K2, Decl(keyofAndIndexedAccess.ts, 281, 41))
|
||||
|
||||
(value: T[K1][K2]) => object[key1][key2] = value;
|
||||
>value : Symbol(value, Decl(keyofAndIndexedAccess.ts, 282, 5))
|
||||
>T : Symbol(T, Decl(keyofAndIndexedAccess.ts, 281, 19))
|
||||
>K1 : Symbol(K1, Decl(keyofAndIndexedAccess.ts, 281, 21))
|
||||
>K2 : Symbol(K2, Decl(keyofAndIndexedAccess.ts, 281, 41))
|
||||
>object : Symbol(object, Decl(keyofAndIndexedAccess.ts, 281, 66))
|
||||
>key1 : Symbol(key1, Decl(keyofAndIndexedAccess.ts, 281, 76))
|
||||
>key2 : Symbol(key2, Decl(keyofAndIndexedAccess.ts, 281, 86))
|
||||
>value : Symbol(value, Decl(keyofAndIndexedAccess.ts, 282, 5))
|
||||
|
||||
// Modified repro from #12573
|
||||
|
||||
declare function one<T>(handler: (t: T) => void): T
|
||||
>one : Symbol(one, Decl(keyofAndIndexedAccess.ts, 282, 53))
|
||||
>T : Symbol(T, Decl(keyofAndIndexedAccess.ts, 286, 21))
|
||||
>handler : Symbol(handler, Decl(keyofAndIndexedAccess.ts, 286, 24))
|
||||
>t : Symbol(t, Decl(keyofAndIndexedAccess.ts, 286, 34))
|
||||
>T : Symbol(T, Decl(keyofAndIndexedAccess.ts, 286, 21))
|
||||
>T : Symbol(T, Decl(keyofAndIndexedAccess.ts, 286, 21))
|
||||
|
||||
var empty = one(() => {}) // inferred as {}, expected
|
||||
>empty : Symbol(empty, Decl(keyofAndIndexedAccess.ts, 287, 3))
|
||||
>one : Symbol(one, Decl(keyofAndIndexedAccess.ts, 282, 53))
|
||||
|
||||
type Handlers<T> = { [K in keyof T]: (t: T[K]) => void }
|
||||
>Handlers : Symbol(Handlers, Decl(keyofAndIndexedAccess.ts, 287, 25))
|
||||
>T : Symbol(T, Decl(keyofAndIndexedAccess.ts, 289, 14))
|
||||
>K : Symbol(K, Decl(keyofAndIndexedAccess.ts, 289, 22))
|
||||
>T : Symbol(T, Decl(keyofAndIndexedAccess.ts, 289, 14))
|
||||
>t : Symbol(t, Decl(keyofAndIndexedAccess.ts, 289, 38))
|
||||
>T : Symbol(T, Decl(keyofAndIndexedAccess.ts, 289, 14))
|
||||
>K : Symbol(K, Decl(keyofAndIndexedAccess.ts, 289, 22))
|
||||
|
||||
declare function on<T>(handlerHash: Handlers<T>): T
|
||||
>on : Symbol(on, Decl(keyofAndIndexedAccess.ts, 289, 56))
|
||||
>T : Symbol(T, Decl(keyofAndIndexedAccess.ts, 290, 20))
|
||||
>handlerHash : Symbol(handlerHash, Decl(keyofAndIndexedAccess.ts, 290, 23))
|
||||
>Handlers : Symbol(Handlers, Decl(keyofAndIndexedAccess.ts, 287, 25))
|
||||
>T : Symbol(T, Decl(keyofAndIndexedAccess.ts, 290, 20))
|
||||
>T : Symbol(T, Decl(keyofAndIndexedAccess.ts, 290, 20))
|
||||
|
||||
var hashOfEmpty1 = on({ test: () => {} }); // {}
|
||||
>hashOfEmpty1 : Symbol(hashOfEmpty1, Decl(keyofAndIndexedAccess.ts, 291, 3))
|
||||
>on : Symbol(on, Decl(keyofAndIndexedAccess.ts, 289, 56))
|
||||
>test : Symbol(test, Decl(keyofAndIndexedAccess.ts, 291, 23))
|
||||
|
||||
var hashOfEmpty2 = on({ test: (x: boolean) => {} }); // { test: boolean }
|
||||
>hashOfEmpty2 : Symbol(hashOfEmpty2, Decl(keyofAndIndexedAccess.ts, 292, 3))
|
||||
>on : Symbol(on, Decl(keyofAndIndexedAccess.ts, 289, 56))
|
||||
>test : Symbol(test, Decl(keyofAndIndexedAccess.ts, 292, 23))
|
||||
>x : Symbol(x, Decl(keyofAndIndexedAccess.ts, 292, 31))
|
||||
|
||||
|
|
|
@ -826,7 +826,7 @@ function f54<T>(obj: T, key: keyof T) {
|
|||
>T : T
|
||||
|
||||
for (let s in obj[key]) {
|
||||
>s : string
|
||||
>s : keyof T[keyof T]
|
||||
>obj[key] : T[keyof T]
|
||||
>obj : T
|
||||
>key : keyof T
|
||||
|
@ -851,7 +851,7 @@ function f55<T, K extends keyof T>(obj: T, key: K) {
|
|||
>K : K
|
||||
|
||||
for (let s in obj[key]) {
|
||||
>s : string
|
||||
>s : keyof T[K]
|
||||
>obj[key] : T[K]
|
||||
>obj : T
|
||||
>key : K
|
||||
|
@ -982,3 +982,223 @@ class OtherPerson {
|
|||
}
|
||||
}
|
||||
|
||||
// Modified repro from #12544
|
||||
|
||||
function path<T, K1 extends keyof T>(obj: T, key1: K1): T[K1];
|
||||
>path : { <T, K1 extends keyof T>(obj: T, key1: K1): T[K1]; <T, K1 extends keyof T, K2 extends keyof T[K1]>(obj: T, key1: K1, key2: K2): T[K1][K2]; <T, K1 extends keyof T, K2 extends keyof T[K1], K3 extends keyof T[K1][K2]>(obj: T, key1: K1, key2: K2, key3: K3): T[K1][K2][K3]; (obj: any, ...keys: (string | number)[]): any; }
|
||||
>T : T
|
||||
>K1 : K1
|
||||
>T : T
|
||||
>obj : T
|
||||
>T : T
|
||||
>key1 : K1
|
||||
>K1 : K1
|
||||
>T : T
|
||||
>K1 : K1
|
||||
|
||||
function path<T, K1 extends keyof T, K2 extends keyof T[K1]>(obj: T, key1: K1, key2: K2): T[K1][K2];
|
||||
>path : { <T, K1 extends keyof T>(obj: T, key1: K1): T[K1]; <T, K1 extends keyof T, K2 extends keyof T[K1]>(obj: T, key1: K1, key2: K2): T[K1][K2]; <T, K1 extends keyof T, K2 extends keyof T[K1], K3 extends keyof T[K1][K2]>(obj: T, key1: K1, key2: K2, key3: K3): T[K1][K2][K3]; (obj: any, ...keys: (string | number)[]): any; }
|
||||
>T : T
|
||||
>K1 : K1
|
||||
>T : T
|
||||
>K2 : K2
|
||||
>T : T
|
||||
>K1 : K1
|
||||
>obj : T
|
||||
>T : T
|
||||
>key1 : K1
|
||||
>K1 : K1
|
||||
>key2 : K2
|
||||
>K2 : K2
|
||||
>T : T
|
||||
>K1 : K1
|
||||
>K2 : K2
|
||||
|
||||
function path<T, K1 extends keyof T, K2 extends keyof T[K1], K3 extends keyof T[K1][K2]>(obj: T, key1: K1, key2: K2, key3: K3): T[K1][K2][K3];
|
||||
>path : { <T, K1 extends keyof T>(obj: T, key1: K1): T[K1]; <T, K1 extends keyof T, K2 extends keyof T[K1]>(obj: T, key1: K1, key2: K2): T[K1][K2]; <T, K1 extends keyof T, K2 extends keyof T[K1], K3 extends keyof T[K1][K2]>(obj: T, key1: K1, key2: K2, key3: K3): T[K1][K2][K3]; (obj: any, ...keys: (string | number)[]): any; }
|
||||
>T : T
|
||||
>K1 : K1
|
||||
>T : T
|
||||
>K2 : K2
|
||||
>T : T
|
||||
>K1 : K1
|
||||
>K3 : K3
|
||||
>T : T
|
||||
>K1 : K1
|
||||
>K2 : K2
|
||||
>obj : T
|
||||
>T : T
|
||||
>key1 : K1
|
||||
>K1 : K1
|
||||
>key2 : K2
|
||||
>K2 : K2
|
||||
>key3 : K3
|
||||
>K3 : K3
|
||||
>T : T
|
||||
>K1 : K1
|
||||
>K2 : K2
|
||||
>K3 : K3
|
||||
|
||||
function path(obj: any, ...keys: (string | number)[]): any;
|
||||
>path : { <T, K1 extends keyof T>(obj: T, key1: K1): T[K1]; <T, K1 extends keyof T, K2 extends keyof T[K1]>(obj: T, key1: K1, key2: K2): T[K1][K2]; <T, K1 extends keyof T, K2 extends keyof T[K1], K3 extends keyof T[K1][K2]>(obj: T, key1: K1, key2: K2, key3: K3): T[K1][K2][K3]; (obj: any, ...keys: (string | number)[]): any; }
|
||||
>obj : any
|
||||
>keys : (string | number)[]
|
||||
|
||||
function path(obj: any, ...keys: (string | number)[]): any {
|
||||
>path : { <T, K1 extends keyof T>(obj: T, key1: K1): T[K1]; <T, K1 extends keyof T, K2 extends keyof T[K1]>(obj: T, key1: K1, key2: K2): T[K1][K2]; <T, K1 extends keyof T, K2 extends keyof T[K1], K3 extends keyof T[K1][K2]>(obj: T, key1: K1, key2: K2, key3: K3): T[K1][K2][K3]; (obj: any, ...keys: (string | number)[]): any; }
|
||||
>obj : any
|
||||
>keys : (string | number)[]
|
||||
|
||||
let result = obj;
|
||||
>result : any
|
||||
>obj : any
|
||||
|
||||
for (let k of keys) {
|
||||
>k : string | number
|
||||
>keys : (string | number)[]
|
||||
|
||||
result = result[k];
|
||||
>result = result[k] : any
|
||||
>result : any
|
||||
>result[k] : any
|
||||
>result : any
|
||||
>k : string | number
|
||||
}
|
||||
return result;
|
||||
>result : any
|
||||
}
|
||||
|
||||
type Thing = {
|
||||
>Thing : Thing
|
||||
|
||||
a: { x: number, y: string },
|
||||
>a : { x: number; y: string; }
|
||||
>x : number
|
||||
>y : string
|
||||
|
||||
b: boolean
|
||||
>b : boolean
|
||||
|
||||
};
|
||||
|
||||
|
||||
function f1(thing: Thing) {
|
||||
>f1 : (thing: Thing) => void
|
||||
>thing : Thing
|
||||
>Thing : Thing
|
||||
|
||||
let x1 = path(thing, 'a'); // { x: number, y: string }
|
||||
>x1 : { x: number; y: string; }
|
||||
>path(thing, 'a') : { x: number; y: string; }
|
||||
>path : { <T, K1 extends keyof T>(obj: T, key1: K1): T[K1]; <T, K1 extends keyof T, K2 extends keyof T[K1]>(obj: T, key1: K1, key2: K2): T[K1][K2]; <T, K1 extends keyof T, K2 extends keyof T[K1], K3 extends keyof T[K1][K2]>(obj: T, key1: K1, key2: K2, key3: K3): T[K1][K2][K3]; (obj: any, ...keys: (string | number)[]): any; }
|
||||
>thing : Thing
|
||||
>'a' : "a"
|
||||
|
||||
let x2 = path(thing, 'a', 'y'); // string
|
||||
>x2 : string
|
||||
>path(thing, 'a', 'y') : string
|
||||
>path : { <T, K1 extends keyof T>(obj: T, key1: K1): T[K1]; <T, K1 extends keyof T, K2 extends keyof T[K1]>(obj: T, key1: K1, key2: K2): T[K1][K2]; <T, K1 extends keyof T, K2 extends keyof T[K1], K3 extends keyof T[K1][K2]>(obj: T, key1: K1, key2: K2, key3: K3): T[K1][K2][K3]; (obj: any, ...keys: (string | number)[]): any; }
|
||||
>thing : Thing
|
||||
>'a' : "a"
|
||||
>'y' : "y"
|
||||
|
||||
let x3 = path(thing, 'b'); // boolean
|
||||
>x3 : boolean
|
||||
>path(thing, 'b') : boolean
|
||||
>path : { <T, K1 extends keyof T>(obj: T, key1: K1): T[K1]; <T, K1 extends keyof T, K2 extends keyof T[K1]>(obj: T, key1: K1, key2: K2): T[K1][K2]; <T, K1 extends keyof T, K2 extends keyof T[K1], K3 extends keyof T[K1][K2]>(obj: T, key1: K1, key2: K2, key3: K3): T[K1][K2][K3]; (obj: any, ...keys: (string | number)[]): any; }
|
||||
>thing : Thing
|
||||
>'b' : "b"
|
||||
|
||||
let x4 = path(thing, ...['a', 'x']); // any
|
||||
>x4 : any
|
||||
>path(thing, ...['a', 'x']) : any
|
||||
>path : { <T, K1 extends keyof T>(obj: T, key1: K1): T[K1]; <T, K1 extends keyof T, K2 extends keyof T[K1]>(obj: T, key1: K1, key2: K2): T[K1][K2]; <T, K1 extends keyof T, K2 extends keyof T[K1], K3 extends keyof T[K1][K2]>(obj: T, key1: K1, key2: K2, key3: K3): T[K1][K2][K3]; (obj: any, ...keys: (string | number)[]): any; }
|
||||
>thing : Thing
|
||||
>...['a', 'x'] : string
|
||||
>['a', 'x'] : string[]
|
||||
>'a' : "a"
|
||||
>'x' : "x"
|
||||
}
|
||||
|
||||
// Repro from comment in #12114
|
||||
|
||||
const assignTo2 = <T, K1 extends keyof T, K2 extends keyof T[K1]>(object: T, key1: K1, key2: K2) =>
|
||||
>assignTo2 : <T, K1 extends keyof T, K2 extends keyof T[K1]>(object: T, key1: K1, key2: K2) => (value: T[K1][K2]) => T[K1][K2]
|
||||
><T, K1 extends keyof T, K2 extends keyof T[K1]>(object: T, key1: K1, key2: K2) => (value: T[K1][K2]) => object[key1][key2] = value : <T, K1 extends keyof T, K2 extends keyof T[K1]>(object: T, key1: K1, key2: K2) => (value: T[K1][K2]) => T[K1][K2]
|
||||
>T : T
|
||||
>K1 : K1
|
||||
>T : T
|
||||
>K2 : K2
|
||||
>T : T
|
||||
>K1 : K1
|
||||
>object : T
|
||||
>T : T
|
||||
>key1 : K1
|
||||
>K1 : K1
|
||||
>key2 : K2
|
||||
>K2 : K2
|
||||
|
||||
(value: T[K1][K2]) => object[key1][key2] = value;
|
||||
>(value: T[K1][K2]) => object[key1][key2] = value : (value: T[K1][K2]) => T[K1][K2]
|
||||
>value : T[K1][K2]
|
||||
>T : T
|
||||
>K1 : K1
|
||||
>K2 : K2
|
||||
>object[key1][key2] = value : T[K1][K2]
|
||||
>object[key1][key2] : T[K1][K2]
|
||||
>object[key1] : T[K1]
|
||||
>object : T
|
||||
>key1 : K1
|
||||
>key2 : K2
|
||||
>value : T[K1][K2]
|
||||
|
||||
// Modified repro from #12573
|
||||
|
||||
declare function one<T>(handler: (t: T) => void): T
|
||||
>one : <T>(handler: (t: T) => void) => T
|
||||
>T : T
|
||||
>handler : (t: T) => void
|
||||
>t : T
|
||||
>T : T
|
||||
>T : T
|
||||
|
||||
var empty = one(() => {}) // inferred as {}, expected
|
||||
>empty : {}
|
||||
>one(() => {}) : {}
|
||||
>one : <T>(handler: (t: T) => void) => T
|
||||
>() => {} : () => void
|
||||
|
||||
type Handlers<T> = { [K in keyof T]: (t: T[K]) => void }
|
||||
>Handlers : Handlers<T>
|
||||
>T : T
|
||||
>K : K
|
||||
>T : T
|
||||
>t : T[K]
|
||||
>T : T
|
||||
>K : K
|
||||
|
||||
declare function on<T>(handlerHash: Handlers<T>): T
|
||||
>on : <T>(handlerHash: Handlers<T>) => T
|
||||
>T : T
|
||||
>handlerHash : Handlers<T>
|
||||
>Handlers : Handlers<T>
|
||||
>T : T
|
||||
>T : T
|
||||
|
||||
var hashOfEmpty1 = on({ test: () => {} }); // {}
|
||||
>hashOfEmpty1 : {}
|
||||
>on({ test: () => {} }) : {}
|
||||
>on : <T>(handlerHash: Handlers<T>) => T
|
||||
>{ test: () => {} } : { test: () => void; }
|
||||
>test : () => void
|
||||
>() => {} : () => void
|
||||
|
||||
var hashOfEmpty2 = on({ test: (x: boolean) => {} }); // { test: boolean }
|
||||
>hashOfEmpty2 : { test: boolean; }
|
||||
>on({ test: (x: boolean) => {} }) : { test: boolean; }
|
||||
>on : <T>(handlerHash: Handlers<T>) => T
|
||||
>{ test: (x: boolean) => {} } : { test: (x: boolean) => void; }
|
||||
>test : (x: boolean) => void
|
||||
>(x: boolean) => {} : (x: boolean) => void
|
||||
>x : boolean
|
||||
|
||||
|
|
|
@ -250,3 +250,45 @@ class OtherPerson {
|
|||
return getProperty(this, "parts")
|
||||
}
|
||||
}
|
||||
|
||||
// Modified repro from #12544
|
||||
|
||||
function path<T, K1 extends keyof T>(obj: T, key1: K1): T[K1];
|
||||
function path<T, K1 extends keyof T, K2 extends keyof T[K1]>(obj: T, key1: K1, key2: K2): T[K1][K2];
|
||||
function path<T, K1 extends keyof T, K2 extends keyof T[K1], K3 extends keyof T[K1][K2]>(obj: T, key1: K1, key2: K2, key3: K3): T[K1][K2][K3];
|
||||
function path(obj: any, ...keys: (string | number)[]): any;
|
||||
function path(obj: any, ...keys: (string | number)[]): any {
|
||||
let result = obj;
|
||||
for (let k of keys) {
|
||||
result = result[k];
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
type Thing = {
|
||||
a: { x: number, y: string },
|
||||
b: boolean
|
||||
};
|
||||
|
||||
|
||||
function f1(thing: Thing) {
|
||||
let x1 = path(thing, 'a'); // { x: number, y: string }
|
||||
let x2 = path(thing, 'a', 'y'); // string
|
||||
let x3 = path(thing, 'b'); // boolean
|
||||
let x4 = path(thing, ...['a', 'x']); // any
|
||||
}
|
||||
|
||||
// Repro from comment in #12114
|
||||
|
||||
const assignTo2 = <T, K1 extends keyof T, K2 extends keyof T[K1]>(object: T, key1: K1, key2: K2) =>
|
||||
(value: T[K1][K2]) => object[key1][key2] = value;
|
||||
|
||||
// Modified repro from #12573
|
||||
|
||||
declare function one<T>(handler: (t: T) => void): T
|
||||
var empty = one(() => {}) // inferred as {}, expected
|
||||
|
||||
type Handlers<T> = { [K in keyof T]: (t: T[K]) => void }
|
||||
declare function on<T>(handlerHash: Handlers<T>): T
|
||||
var hashOfEmpty1 = on({ test: () => {} }); // {}
|
||||
var hashOfEmpty2 = on({ test: (x: boolean) => {} }); // { test: boolean }
|
|
@ -120,4 +120,29 @@ function f10(foo: Foo) {
|
|||
let x = validate(foo); // { a: number, readonly b: string }
|
||||
let y = clone(foo); // { a?: number, b: string }
|
||||
let z = validateAndClone(foo); // { a: number, b: string }
|
||||
}
|
||||
}
|
||||
|
||||
// Repro from #12606
|
||||
|
||||
type Func<T> = (...args: any[]) => T;
|
||||
type Spec<T> = {
|
||||
[P in keyof T]: Func<T[P]> | Spec<T[P]> ;
|
||||
};
|
||||
|
||||
/**
|
||||
* Given a spec object recursively mapping properties to functions, creates a function
|
||||
* producing an object of the same structure, by mapping each property to the result
|
||||
* of calling its associated function with the supplied arguments.
|
||||
*/
|
||||
declare function applySpec<T>(obj: Spec<T>): (...args: any[]) => T;
|
||||
|
||||
// Infers g1: (...args: any[]) => { sum: number, nested: { mul: string } }
|
||||
var g1 = applySpec({
|
||||
sum: (a: any) => 3,
|
||||
nested: {
|
||||
mul: (b: any) => "n"
|
||||
}
|
||||
});
|
||||
|
||||
// Infers g2: (...args: any[]) => { foo: { bar: { baz: boolean } } }
|
||||
var g2 = applySpec({ foo: { bar: { baz: (x: any) => true } } });
|
Loading…
Reference in a new issue