mirror of
https://github.com/microsoft/TypeScript.git
synced 2026-02-12 12:57:11 -06:00
Respect readonly mapped type modifier when mapping arrays and tuples
This commit is contained in:
parent
52b82560e8
commit
903863a87a
@ -3612,7 +3612,8 @@ namespace ts {
|
||||
createRestTypeNode(createArrayTypeNode(tupleConstituentNodes[i])) :
|
||||
createOptionalTypeNode(tupleConstituentNodes[i]);
|
||||
}
|
||||
return createTupleTypeNode(tupleConstituentNodes);
|
||||
const tupleTypeNode = createTupleTypeNode(tupleConstituentNodes);
|
||||
return (<TupleType>type.target).readonly ? createTypeReferenceNode("Readonly", [tupleTypeNode]) : tupleTypeNode;
|
||||
}
|
||||
}
|
||||
if (context.encounteredError || (context.flags & NodeBuilderFlags.AllowEmptyTuple)) {
|
||||
@ -5923,7 +5924,7 @@ namespace ts {
|
||||
function getBaseTypes(type: InterfaceType): BaseType[] {
|
||||
if (!type.resolvedBaseTypes) {
|
||||
if (type.objectFlags & ObjectFlags.Tuple) {
|
||||
type.resolvedBaseTypes = [createArrayType(getUnionType(type.typeParameters || emptyArray))];
|
||||
type.resolvedBaseTypes = [createArrayType(getUnionType(type.typeParameters || emptyArray), (<TupleType>type).readonly)];
|
||||
}
|
||||
else if (type.symbol.flags & (SymbolFlags.Class | SymbolFlags.Interface)) {
|
||||
if (type.symbol.flags & SymbolFlags.Class) {
|
||||
@ -7630,7 +7631,7 @@ namespace ts {
|
||||
const typeVariable = getHomomorphicTypeVariable(type);
|
||||
if (typeVariable) {
|
||||
const constraint = getConstraintOfTypeParameter(typeVariable);
|
||||
if (constraint && (isArrayType(constraint) || isReadonlyArrayType(constraint) || isTupleType(constraint))) {
|
||||
if (constraint && (isArrayType(constraint) || isTupleType(constraint))) {
|
||||
const mapper = makeUnaryTypeMapper(typeVariable, constraint);
|
||||
return instantiateType(type, combineTypeMappers(mapper, type.mapper));
|
||||
}
|
||||
@ -9022,12 +9023,8 @@ namespace ts {
|
||||
return createTypeFromGenericGlobalType(getGlobalIterableIteratorType(/*reportErrors*/ true), [iteratedType]);
|
||||
}
|
||||
|
||||
function createArrayType(elementType: Type): ObjectType {
|
||||
return createTypeFromGenericGlobalType(globalArrayType, [elementType]);
|
||||
}
|
||||
|
||||
function createReadonlyArrayType(elementType: Type): ObjectType {
|
||||
return createTypeFromGenericGlobalType(globalReadonlyArrayType, [elementType]);
|
||||
function createArrayType(elementType: Type, readonly?: boolean): ObjectType {
|
||||
return createTypeFromGenericGlobalType(readonly ? globalReadonlyArrayType : globalArrayType, [elementType]);
|
||||
}
|
||||
|
||||
function getTypeFromArrayTypeNode(node: ArrayTypeNode): Type {
|
||||
@ -9045,7 +9042,7 @@ namespace ts {
|
||||
//
|
||||
// Note that the generic type created by this function has no symbol associated with it. The same
|
||||
// is true for each of the synthesized type parameters.
|
||||
function createTupleTypeOfArity(arity: number, minLength: number, hasRestElement: boolean, associatedNames: __String[] | undefined): TupleType {
|
||||
function createTupleTypeOfArity(arity: number, minLength: number, hasRestElement: boolean, readonly: boolean, associatedNames: __String[] | undefined): TupleType {
|
||||
let typeParameters: TypeParameter[] | undefined;
|
||||
const properties: Symbol[] = [];
|
||||
const maxLength = hasRestElement ? arity - 1 : arity;
|
||||
@ -9054,7 +9051,8 @@ namespace ts {
|
||||
for (let i = 0; i < arity; i++) {
|
||||
const typeParameter = typeParameters[i] = createTypeParameter();
|
||||
if (i < maxLength) {
|
||||
const property = createSymbol(SymbolFlags.Property | (i >= minLength ? SymbolFlags.Optional : 0), "" + i as __String);
|
||||
const property = createSymbol(SymbolFlags.Property | (i >= minLength ? SymbolFlags.Optional : 0),
|
||||
"" + i as __String, readonly ? CheckFlags.Readonly : 0);
|
||||
property.type = typeParameter;
|
||||
properties.push(property);
|
||||
}
|
||||
@ -9083,25 +9081,26 @@ namespace ts {
|
||||
type.declaredNumberIndexInfo = undefined;
|
||||
type.minLength = minLength;
|
||||
type.hasRestElement = hasRestElement;
|
||||
type.readonly = readonly;
|
||||
type.associatedNames = associatedNames;
|
||||
return type;
|
||||
}
|
||||
|
||||
function getTupleTypeOfArity(arity: number, minLength: number, hasRestElement: boolean, associatedNames?: __String[]): GenericType {
|
||||
const key = arity + (hasRestElement ? "+" : ",") + minLength + (associatedNames && associatedNames.length ? "," + associatedNames.join(",") : "");
|
||||
function getTupleTypeOfArity(arity: number, minLength: number, hasRestElement: boolean, readonly: boolean, associatedNames?: __String[]): GenericType {
|
||||
const key = arity + (hasRestElement ? "+" : ",") + minLength + (readonly ? "R" : "") + (associatedNames && associatedNames.length ? "," + associatedNames.join(",") : "");
|
||||
let type = tupleTypes.get(key);
|
||||
if (!type) {
|
||||
tupleTypes.set(key, type = createTupleTypeOfArity(arity, minLength, hasRestElement, associatedNames));
|
||||
tupleTypes.set(key, type = createTupleTypeOfArity(arity, minLength, hasRestElement, readonly, associatedNames));
|
||||
}
|
||||
return type;
|
||||
}
|
||||
|
||||
function createTupleType(elementTypes: ReadonlyArray<Type>, minLength = elementTypes.length, hasRestElement = false, associatedNames?: __String[]) {
|
||||
function createTupleType(elementTypes: ReadonlyArray<Type>, minLength = elementTypes.length, hasRestElement = false, readonly = false, associatedNames?: __String[]) {
|
||||
const arity = elementTypes.length;
|
||||
if (arity === 1 && hasRestElement) {
|
||||
return createArrayType(elementTypes[0]);
|
||||
}
|
||||
const tupleType = getTupleTypeOfArity(arity, minLength, arity > 0 && hasRestElement, associatedNames);
|
||||
const tupleType = getTupleTypeOfArity(arity, minLength, arity > 0 && hasRestElement, readonly, associatedNames);
|
||||
return elementTypes.length ? createTypeReference(tupleType, elementTypes) : tupleType;
|
||||
}
|
||||
|
||||
@ -9130,6 +9129,7 @@ namespace ts {
|
||||
(type.typeArguments || emptyArray).slice(index),
|
||||
Math.max(0, tuple.minLength - index),
|
||||
tuple.hasRestElement,
|
||||
tuple.readonly,
|
||||
tuple.associatedNames && tuple.associatedNames.slice(index),
|
||||
);
|
||||
}
|
||||
@ -10694,7 +10694,7 @@ namespace ts {
|
||||
}
|
||||
// Keep the flags from the symbol we're instantiating. Mark that is instantiated, and
|
||||
// also transient so that we can just store data on it directly.
|
||||
const result = createSymbol(symbol.flags, symbol.escapedName, CheckFlags.Instantiated | getCheckFlags(symbol) & (CheckFlags.Late | CheckFlags.OptionalParameter | CheckFlags.RestParameter));
|
||||
const result = createSymbol(symbol.flags, symbol.escapedName, CheckFlags.Instantiated | getCheckFlags(symbol) & (CheckFlags.Readonly | CheckFlags.Late | CheckFlags.OptionalParameter | CheckFlags.RestParameter));
|
||||
result.declarations = symbol.declarations;
|
||||
result.parent = symbol.parent;
|
||||
result.target = symbol;
|
||||
@ -10825,11 +10825,11 @@ namespace ts {
|
||||
return errorType;
|
||||
}
|
||||
type.instantiating = true;
|
||||
const modifiers = getMappedTypeModifiers(type);
|
||||
const result = mapType(mappedTypeVariable, t => {
|
||||
if (t.flags & (TypeFlags.AnyOrUnknown | TypeFlags.InstantiableNonPrimitive | TypeFlags.Object | TypeFlags.Intersection) && t !== wildcardType) {
|
||||
const replacementMapper = createReplacementMapper(typeVariable, t, mapper);
|
||||
return isArrayType(t) ? createArrayType(instantiateMappedTypeTemplate(type, numberType, /*isOptional*/ true, replacementMapper)) :
|
||||
isReadonlyArrayType(t) ? createReadonlyArrayType(instantiateMappedTypeTemplate(type, numberType, /*isOptional*/ true, replacementMapper)) :
|
||||
return isArrayType(t) ? createArrayType(instantiateMappedTypeTemplate(type, numberType, /*isOptional*/ true, replacementMapper), getModifiedReadonlyState(isReadonlyArrayType(t), modifiers)) :
|
||||
isTupleType(t) ? instantiateMappedTupleType(t, type, replacementMapper) :
|
||||
instantiateAnonymousType(type, replacementMapper);
|
||||
}
|
||||
@ -10842,6 +10842,10 @@ namespace ts {
|
||||
return instantiateAnonymousType(type, mapper);
|
||||
}
|
||||
|
||||
function getModifiedReadonlyState(state: boolean, modifiers: MappedTypeModifiers) {
|
||||
return modifiers & MappedTypeModifiers.IncludeReadonly ? true : modifiers & MappedTypeModifiers.ExcludeReadonly ? false : state;
|
||||
}
|
||||
|
||||
function instantiateMappedTupleType(tupleType: TupleTypeReference, mappedType: MappedType, mapper: TypeMapper) {
|
||||
const minLength = tupleType.target.minLength;
|
||||
const elementTypes = map(tupleType.typeArguments || emptyArray, (_, i) =>
|
||||
@ -10850,7 +10854,8 @@ namespace ts {
|
||||
const newMinLength = modifiers & MappedTypeModifiers.IncludeOptional ? 0 :
|
||||
modifiers & MappedTypeModifiers.ExcludeOptional ? getTypeReferenceArity(tupleType) - (tupleType.target.hasRestElement ? 1 : 0) :
|
||||
minLength;
|
||||
return createTupleType(elementTypes, newMinLength, tupleType.target.hasRestElement, tupleType.target.associatedNames);
|
||||
const newReadonly = getModifiedReadonlyState(tupleType.target.readonly, modifiers);
|
||||
return createTupleType(elementTypes, newMinLength, tupleType.target.hasRestElement, newReadonly, tupleType.target.associatedNames);
|
||||
}
|
||||
|
||||
function instantiateMappedTypeTemplate(type: MappedType, key: Type, isOptional: boolean, mapper: TypeMapper) {
|
||||
@ -12608,7 +12613,7 @@ namespace ts {
|
||||
errorInfo = saveErrorInfo;
|
||||
}
|
||||
}
|
||||
else if (isTupleType(source) && (isArrayType(target) || isReadonlyArrayType(target)) || isArrayType(source) && isReadonlyArrayType(target)) {
|
||||
else if (isTupleType(source) && isArrayType(target) || isArrayType(source) && isReadonlyArrayType(target)) {
|
||||
return isRelatedTo(getIndexTypeOfType(source, IndexKind.Number) || anyType, getIndexTypeOfType(target, IndexKind.Number) || anyType, reportErrors);
|
||||
}
|
||||
// Even if relationship doesn't hold for unions, intersections, or generic type references,
|
||||
@ -13443,7 +13448,7 @@ namespace ts {
|
||||
}
|
||||
|
||||
function isArrayType(type: Type): boolean {
|
||||
return !!(getObjectFlags(type) & ObjectFlags.Reference) && (<TypeReference>type).target === globalArrayType;
|
||||
return !!(getObjectFlags(type) & ObjectFlags.Reference) && ((<TypeReference>type).target === globalArrayType || (<TypeReference>type).target === globalReadonlyArrayType);
|
||||
}
|
||||
|
||||
function isReadonlyArrayType(type: Type): boolean {
|
||||
@ -13457,8 +13462,7 @@ namespace ts {
|
||||
function isArrayLikeType(type: Type): boolean {
|
||||
// A type is array-like if it is a reference to the global Array or global ReadonlyArray type,
|
||||
// or if it is not the undefined or null type and if it is assignable to ReadonlyArray<any>
|
||||
return getObjectFlags(type) & ObjectFlags.Reference && ((<TypeReference>type).target === globalArrayType || (<TypeReference>type).target === globalReadonlyArrayType) ||
|
||||
!(type.flags & TypeFlags.Nullable) && isTypeAssignableTo(type, anyReadonlyArrayType);
|
||||
return isArrayType(type) || !(type.flags & TypeFlags.Nullable) && isTypeAssignableTo(type, anyReadonlyArrayType);
|
||||
}
|
||||
|
||||
function isEmptyArrayLiteralType(type: Type): boolean {
|
||||
@ -14063,16 +14067,13 @@ namespace ts {
|
||||
// For arrays and tuples we infer new arrays and tuples where the reverse mapping has been
|
||||
// applied to the element type(s).
|
||||
if (isArrayType(source)) {
|
||||
return createArrayType(inferReverseMappedType((<TypeReference>source).typeArguments![0], target, constraint));
|
||||
}
|
||||
if (isReadonlyArrayType(source)) {
|
||||
return createReadonlyArrayType(inferReverseMappedType((<TypeReference>source).typeArguments![0], target, constraint));
|
||||
return createArrayType(inferReverseMappedType((<TypeReference>source).typeArguments![0], target, constraint), isReadonlyArrayType(source));
|
||||
}
|
||||
if (isTupleType(source)) {
|
||||
const elementTypes = map(source.typeArguments || emptyArray, t => inferReverseMappedType(t, target, constraint));
|
||||
const minLength = getMappedTypeModifiers(target) & MappedTypeModifiers.IncludeOptional ?
|
||||
getTypeReferenceArity(source) - (source.target.hasRestElement ? 1 : 0) : source.target.minLength;
|
||||
return createTupleType(elementTypes, minLength, source.target.hasRestElement, source.target.associatedNames);
|
||||
return createTupleType(elementTypes, minLength, source.target.hasRestElement, source.target.readonly, source.target.associatedNames);
|
||||
}
|
||||
// For all other object types we infer a new object type where the reverse mapping has been
|
||||
// applied to the type of each property.
|
||||
@ -17948,7 +17949,9 @@ namespace ts {
|
||||
return createTupleType(elementTypes, minLength, hasRestElement);
|
||||
}
|
||||
}
|
||||
return getArrayLiteralType(elementTypes, UnionReduction.Subtype);
|
||||
return createArrayType(elementTypes.length ?
|
||||
getUnionType(elementTypes, UnionReduction.Subtype) :
|
||||
strictNullChecks ? implicitNeverType : undefinedWideningType);
|
||||
}
|
||||
|
||||
function getArrayLiteralTupleTypeIfApplicable(elementTypes: Type[], contextualType: Type | undefined, hasRestElement: boolean, elementCount = elementTypes.length) {
|
||||
@ -17977,12 +17980,6 @@ namespace ts {
|
||||
}
|
||||
}
|
||||
|
||||
function getArrayLiteralType(elementTypes: Type[], unionReduction = UnionReduction.Literal) {
|
||||
return createArrayType(elementTypes.length ?
|
||||
getUnionType(elementTypes, unionReduction) :
|
||||
strictNullChecks ? implicitNeverType : undefinedWideningType);
|
||||
}
|
||||
|
||||
function isNumericName(name: DeclarationName): boolean {
|
||||
switch (name.kind) {
|
||||
case SyntaxKind.ComputedPropertyName:
|
||||
@ -21276,7 +21273,7 @@ namespace ts {
|
||||
}
|
||||
const minArgumentCount = getMinArgumentCount(source);
|
||||
const minLength = minArgumentCount < start ? 0 : minArgumentCount - start;
|
||||
return createTupleType(types, minLength, !!restType, names);
|
||||
return createTupleType(types, minLength, !!restType, /*readonly*/ false, names);
|
||||
}
|
||||
|
||||
function getParameterCount(signature: Signature) {
|
||||
|
||||
@ -4057,6 +4057,7 @@ namespace ts {
|
||||
export interface TupleType extends GenericType {
|
||||
minLength: number;
|
||||
hasRestElement: boolean;
|
||||
readonly: boolean;
|
||||
associatedNames?: __String[];
|
||||
}
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user