mirror of
https://github.com/microsoft/TypeScript.git
synced 2025-11-18 17:21:48 +00:00
Template literal types and mapped type 'as' clauses (#40336)
* Initial implementation of string template types
* Accept new API baselines
* Accept new baselines
* Unified checking for large cross product union types
* Accept new baselines
* Ensure errors from union type resolution are reported
* Accept new baselines
* Compute constraints for string template types
* Support `as T` clause in mapped types
* Accept new API baselines
* Add missing semicolon
* Add checking of `as T` clauses
* Support casing modifiers in string template types
* Accept new baselines
* Bump keyword maximum length
* fix anders
* Revert "fix anders"
This reverts commit b3178d4618.
* Properly handle 'as T' clause with keyof for mapped type
* Fix lint error
* Single character inferences and anchored end span matching
* Fewer array copy operations in template literal type resolution
* Handle cases where 'as T' maps multiple properties onto one
* Fix lint error
* Store key type instead of type mapper in MappedSymbol
* No constraint on `in T` type when `as N` clause present
* Rename from TemplateType to TemplateLiteralType
* Accept new API baselines
* Add tests
* Accept new baselines
* Address CR feedback
* Accept new API baselines
Co-authored-by: Erich Gamma <egamma@microsoft.com>
This commit is contained in:
co-authored by
Erich Gamma
parent
96b0832cf6
commit
6f0c91c4cb
+261
-53
@@ -698,6 +698,7 @@ namespace ts {
|
||||
const intersectionTypes = new Map<string, Type>();
|
||||
const literalTypes = new Map<string, LiteralType>();
|
||||
const indexedAccessTypes = new Map<string, IndexedAccessType>();
|
||||
const templateLiteralTypes = new Map<string, TemplateLiteralType>();
|
||||
const substitutionTypes = new Map<string, SubstitutionType>();
|
||||
const evolvingArrayTypes: EvolvingArrayType[] = [];
|
||||
const undefinedProperties: SymbolTable = new Map();
|
||||
@@ -748,6 +749,7 @@ namespace ts {
|
||||
const stringNumberSymbolType = getUnionType([stringType, numberType, esSymbolType]);
|
||||
const keyofConstraintType = keyofStringsOnly ? stringType : stringNumberSymbolType;
|
||||
const numberOrBigIntType = getUnionType([numberType, bigintType]);
|
||||
const templateConstraintType = getUnionType([stringType, numberType, booleanType, bigintType]);
|
||||
|
||||
const restrictiveMapper: TypeMapper = makeFunctionTypeMapper(t => t.flags & TypeFlags.TypeParameter ? getRestrictiveTypeParameter(<TypeParameter>t) : t);
|
||||
const permissiveMapper: TypeMapper = makeFunctionTypeMapper(t => t.flags & TypeFlags.TypeParameter ? wildcardType : t);
|
||||
@@ -4489,6 +4491,19 @@ namespace ts {
|
||||
const indexTypeNode = typeToTypeNodeHelper(indexedType, context);
|
||||
return factory.createTypeOperatorNode(SyntaxKind.KeyOfKeyword, indexTypeNode);
|
||||
}
|
||||
if (type.flags & TypeFlags.TemplateLiteral) {
|
||||
const texts = (<TemplateLiteralType>type).texts;
|
||||
const casings = (<TemplateLiteralType>type).casings;
|
||||
const types = (<TemplateLiteralType>type).types;
|
||||
const templateHead = factory.createTemplateHead(texts[0]);
|
||||
const templateSpans = factory.createNodeArray(
|
||||
map(types, (t, i) => factory.createTemplateLiteralTypeSpan(
|
||||
casings[i],
|
||||
typeToTypeNodeHelper(t, context),
|
||||
(i < types.length - 1 ? factory.createTemplateMiddle : factory.createTemplateTail)(texts[i + 1]))));
|
||||
context.approximateLength += 2;
|
||||
return factory.createTemplateLiteralType(templateHead, templateSpans);
|
||||
}
|
||||
if (type.flags & TypeFlags.IndexedAccess) {
|
||||
const objectTypeNode = typeToTypeNodeHelper((<IndexedAccessType>type).objectType, context);
|
||||
const indexTypeNode = typeToTypeNodeHelper((<IndexedAccessType>type).indexType, context);
|
||||
@@ -4541,8 +4556,9 @@ namespace ts {
|
||||
appropriateConstraintTypeNode = typeToTypeNodeHelper(getConstraintTypeFromMappedType(type), context);
|
||||
}
|
||||
const typeParameterNode = typeParameterToDeclarationWithConstraint(getTypeParameterFromMappedType(type), context, appropriateConstraintTypeNode);
|
||||
const nameTypeNode = type.declaration.nameType ? typeToTypeNodeHelper(getNameTypeFromMappedType(type)!, context) : undefined;
|
||||
const templateTypeNode = typeToTypeNodeHelper(getTemplateTypeFromMappedType(type), context);
|
||||
const mappedTypeNode = factory.createMappedTypeNode(readonlyToken, typeParameterNode, questionToken, templateTypeNode);
|
||||
const mappedTypeNode = factory.createMappedTypeNode(readonlyToken, typeParameterNode, nameTypeNode, questionToken, templateTypeNode);
|
||||
context.approximateLength += 10;
|
||||
return setEmitFlags(mappedTypeNode, EmitFlags.SingleLine);
|
||||
}
|
||||
@@ -10350,9 +10366,6 @@ namespace ts {
|
||||
// bound includes those keys that are known to always be present, for example because
|
||||
// because of constraints on type parameters (e.g. 'keyof T' for a constrained T).
|
||||
function getLowerBoundOfKeyType(type: Type): Type {
|
||||
if (type.flags & (TypeFlags.Any | TypeFlags.Primitive)) {
|
||||
return type;
|
||||
}
|
||||
if (type.flags & TypeFlags.Index) {
|
||||
const t = getApparentType((<IndexType>type).type);
|
||||
return isGenericTupleType(t) ? getKnownKeysOfTupleType(t) : getIndexType(t);
|
||||
@@ -10373,7 +10386,7 @@ namespace ts {
|
||||
if (type.flags & TypeFlags.Intersection) {
|
||||
return getIntersectionType(sameMap((<UnionType>type).types, getLowerBoundOfKeyType));
|
||||
}
|
||||
return neverType;
|
||||
return type;
|
||||
}
|
||||
|
||||
/** Resolve the members of a mapped type { [P in K]: T } */
|
||||
@@ -10387,6 +10400,7 @@ namespace ts {
|
||||
// and T as the template type.
|
||||
const typeParameter = getTypeParameterFromMappedType(type);
|
||||
const constraintType = getConstraintTypeFromMappedType(type);
|
||||
const nameType = getNameTypeFromMappedType(<MappedType>type.target || type);
|
||||
const templateType = getTemplateTypeFromMappedType(<MappedType>type.target || type);
|
||||
const modifiersType = getApparentType(getModifiersTypeFromMappedType(type)); // The 'T' in 'keyof T'
|
||||
const templateModifiers = getMappedTypeModifiers(type);
|
||||
@@ -10408,22 +10422,23 @@ namespace ts {
|
||||
}
|
||||
setStructuredTypeMembers(type, members, emptyArray, emptyArray, stringIndexInfo, numberIndexInfo);
|
||||
|
||||
function addMemberForKeyType(t: Type) {
|
||||
// Create a mapper from T to the current iteration type constituent. Then, if the
|
||||
// mapped type is itself an instantiated type, combine the iteration mapper with the
|
||||
// instantiation mapper.
|
||||
const templateMapper = appendTypeMapping(type.mapper, typeParameter, t);
|
||||
function addMemberForKeyType(keyType: Type) {
|
||||
const propNameType = nameType ? instantiateType(nameType, appendTypeMapping(type.mapper, typeParameter, keyType)) : keyType;
|
||||
forEachType(propNameType, t => addMemberForKeyTypeWorker(keyType, t));
|
||||
}
|
||||
|
||||
function addMemberForKeyTypeWorker(keyType: Type, propNameType: Type) {
|
||||
// If the current iteration type constituent is a string literal type, create a property.
|
||||
// Otherwise, for type string create a string index signature.
|
||||
if (isTypeUsableAsPropertyName(t)) {
|
||||
const propName = getPropertyNameFromType(t);
|
||||
if (isTypeUsableAsPropertyName(propNameType)) {
|
||||
const propName = getPropertyNameFromType(propNameType);
|
||||
// String enum members from separate enums with identical values
|
||||
// are distinct types with the same property name. Make the resulting
|
||||
// property symbol's name type be the union of those enum member types.
|
||||
const existingProp = members.get(propName) as MappedSymbol | undefined;
|
||||
if (existingProp) {
|
||||
existingProp.nameType = getUnionType([existingProp.nameType!, t]);
|
||||
existingProp.mapper = appendTypeMapping(type.mapper, typeParameter, existingProp.nameType);
|
||||
existingProp.nameType = getUnionType([existingProp.nameType!, propNameType]);
|
||||
existingProp.keyType = getUnionType([existingProp.keyType, keyType]);
|
||||
}
|
||||
else {
|
||||
const modifiersProp = getPropertyOfType(modifiersType, propName);
|
||||
@@ -10435,19 +10450,20 @@ namespace ts {
|
||||
const prop = <MappedSymbol>createSymbol(SymbolFlags.Property | (isOptional ? SymbolFlags.Optional : 0), propName,
|
||||
CheckFlags.Mapped | (isReadonly ? CheckFlags.Readonly : 0) | (stripOptional ? CheckFlags.StripOptional : 0));
|
||||
prop.mappedType = type;
|
||||
prop.nameType = propNameType;
|
||||
prop.keyType = keyType;
|
||||
if (modifiersProp) {
|
||||
prop.syntheticOrigin = modifiersProp;
|
||||
prop.declarations = modifiersProp.declarations;
|
||||
}
|
||||
prop.nameType = t;
|
||||
prop.mapper = templateMapper;
|
||||
members.set(propName, prop);
|
||||
}
|
||||
}
|
||||
else if (t.flags & (TypeFlags.Any | TypeFlags.String | TypeFlags.Number | TypeFlags.Enum)) {
|
||||
const propType = instantiateType(templateType, templateMapper);
|
||||
if (t.flags & (TypeFlags.Any | TypeFlags.String)) {
|
||||
stringIndexInfo = createIndexInfo(propType, !!(templateModifiers & MappedTypeModifiers.IncludeReadonly));
|
||||
else if (propNameType.flags & (TypeFlags.Any | TypeFlags.String | TypeFlags.Number | TypeFlags.Enum)) {
|
||||
const propType = instantiateType(templateType, appendTypeMapping(type.mapper, typeParameter, keyType));
|
||||
if (propNameType.flags & (TypeFlags.Any | TypeFlags.String)) {
|
||||
stringIndexInfo = createIndexInfo(stringIndexInfo ? getUnionType([stringIndexInfo.type, propType]) : propType,
|
||||
!!(templateModifiers & MappedTypeModifiers.IncludeReadonly));
|
||||
}
|
||||
else {
|
||||
numberIndexInfo = createIndexInfo(numberIndexInfo ? getUnionType([numberIndexInfo.type, propType]) : propType,
|
||||
@@ -10459,12 +10475,14 @@ namespace ts {
|
||||
|
||||
function getTypeOfMappedSymbol(symbol: MappedSymbol) {
|
||||
if (!symbol.type) {
|
||||
const mappedType = symbol.mappedType;
|
||||
if (!pushTypeResolution(symbol, TypeSystemPropertyName.Type)) {
|
||||
symbol.mappedType.containsError = true;
|
||||
mappedType.containsError = true;
|
||||
return errorType;
|
||||
}
|
||||
const templateType = getTemplateTypeFromMappedType(<MappedType>symbol.mappedType.target || symbol.mappedType);
|
||||
const propType = instantiateType(templateType, symbol.mapper);
|
||||
const templateType = getTemplateTypeFromMappedType(<MappedType>mappedType.target || mappedType);
|
||||
const mapper = appendTypeMapping(mappedType.mapper, getTypeParameterFromMappedType(mappedType), symbol.keyType);
|
||||
const propType = instantiateType(templateType, mapper);
|
||||
// When creating an optional property in strictNullChecks mode, if 'undefined' isn't assignable to the
|
||||
// type, we include 'undefined' in the type. Similarly, when creating a non-optional property in strictNullChecks
|
||||
// mode, if the underlying property is optional we remove 'undefined' from the type.
|
||||
@@ -10472,11 +10490,10 @@ namespace ts {
|
||||
symbol.checkFlags & CheckFlags.StripOptional ? getTypeWithFacts(propType, TypeFacts.NEUndefined) :
|
||||
propType;
|
||||
if (!popTypeResolution()) {
|
||||
error(currentNode, Diagnostics.Type_of_property_0_circularly_references_itself_in_mapped_type_1, symbolToString(symbol), typeToString(symbol.mappedType));
|
||||
error(currentNode, Diagnostics.Type_of_property_0_circularly_references_itself_in_mapped_type_1, symbolToString(symbol), typeToString(mappedType));
|
||||
type = errorType;
|
||||
}
|
||||
symbol.type = type;
|
||||
symbol.mapper = undefined!;
|
||||
}
|
||||
return symbol.type;
|
||||
}
|
||||
@@ -10491,6 +10508,12 @@ namespace ts {
|
||||
(type.constraintType = getConstraintOfTypeParameter(getTypeParameterFromMappedType(type)) || errorType);
|
||||
}
|
||||
|
||||
function getNameTypeFromMappedType(type: MappedType) {
|
||||
return type.declaration.nameType ?
|
||||
type.nameType || (type.nameType = instantiateType(getTypeFromTypeNode(type.declaration.nameType), type.mapper)) :
|
||||
undefined;
|
||||
}
|
||||
|
||||
function getTemplateTypeFromMappedType(type: MappedType) {
|
||||
return type.templateType ||
|
||||
(type.templateType = type.declaration.type ?
|
||||
@@ -10784,7 +10807,7 @@ namespace ts {
|
||||
}
|
||||
|
||||
function getBaseConstraintOfType(type: Type): Type | undefined {
|
||||
if (type.flags & (TypeFlags.InstantiableNonPrimitive | TypeFlags.UnionOrIntersection)) {
|
||||
if (type.flags & (TypeFlags.InstantiableNonPrimitive | TypeFlags.UnionOrIntersection | TypeFlags.TemplateLiteral)) {
|
||||
const constraint = getResolvedBaseConstraint(<InstantiableType | UnionOrIntersectionType>type);
|
||||
return constraint !== noConstraintType && constraint !== circularConstraintType ? constraint : undefined;
|
||||
}
|
||||
@@ -10878,6 +10901,11 @@ namespace ts {
|
||||
if (t.flags & TypeFlags.Index) {
|
||||
return keyofConstraintType;
|
||||
}
|
||||
if (t.flags & TypeFlags.TemplateLiteral) {
|
||||
const types = (<TemplateLiteralType>t).types;
|
||||
const constraints = mapDefined(types, getBaseConstraint);
|
||||
return constraints.length === types.length ? getTemplateLiteralType((<TemplateLiteralType>t).texts, (<TemplateLiteralType>t).casings, constraints) : stringType;
|
||||
}
|
||||
if (t.flags & TypeFlags.IndexedAccess) {
|
||||
const baseObjectType = getBaseConstraint((<IndexedAccessType>t).objectType);
|
||||
const baseIndexType = getBaseConstraint((<IndexedAccessType>t).indexType);
|
||||
@@ -10955,7 +10983,7 @@ namespace ts {
|
||||
|
||||
function getResolvedApparentTypeOfMappedType(type: MappedType) {
|
||||
const typeVariable = getHomomorphicTypeVariable(type);
|
||||
if (typeVariable) {
|
||||
if (typeVariable && !type.declaration.nameType) {
|
||||
const constraint = getConstraintOfTypeParameter(typeVariable);
|
||||
if (constraint && (isArrayType(constraint) || isTupleType(constraint))) {
|
||||
return instantiateType(type, prependTypeMapping(typeVariable, constraint, type.mapper));
|
||||
@@ -11895,6 +11923,11 @@ namespace ts {
|
||||
grandParent.kind === SyntaxKind.NamedTupleMember && (<NamedTupleMember>grandParent).dotDotDotToken) {
|
||||
inferences = append(inferences, createArrayType(unknownType));
|
||||
}
|
||||
// When an 'infer T' declaration is immediately contained in a string template type, we infer a 'string'
|
||||
// constraint.
|
||||
else if (grandParent.kind === SyntaxKind.TemplateLiteralTypeSpan) {
|
||||
inferences = append(inferences, stringType);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -12720,7 +12753,9 @@ namespace ts {
|
||||
// Transform [A, ...(X | Y | Z)] into [A, ...X] | [A, ...Y] | [A, ...Z]
|
||||
const unionIndex = findIndex(elementTypes, (t, i) => !!(target.elementFlags[i] & ElementFlags.Variadic && t.flags & (TypeFlags.Never | TypeFlags.Union)));
|
||||
if (unionIndex >= 0) {
|
||||
return mapType(elementTypes[unionIndex], t => createNormalizedTupleType(target, replaceElement(elementTypes, unionIndex, t)));
|
||||
return checkCrossProductUnion(map(elementTypes, (t, i) => target.elementFlags[i] & ElementFlags.Variadic ? t : unknownType)) ?
|
||||
mapType(elementTypes[unionIndex], t => createNormalizedTupleType(target, replaceElement(elementTypes, unionIndex, t))) :
|
||||
errorType;
|
||||
}
|
||||
// If there are no variadic elements with non-generic types, just create a type reference with the same target type.
|
||||
const spreadIndex = findIndex(elementTypes, (t, i) => !!(target.elementFlags[i] & ElementFlags.Variadic) && !(t.flags & TypeFlags.InstantiableNonPrimitive) && !isGenericMappedType(t));
|
||||
@@ -13257,9 +13292,7 @@ namespace ts {
|
||||
// We are attempting to construct a type of the form X & (A | B) & Y. Transform this into a type of
|
||||
// the form X & A & Y | X & B & Y and recursively reduce until no union type constituents remain.
|
||||
// If the estimated size of the resulting union type exceeds 100000 constituents, report an error.
|
||||
const size = reduceLeft(typeSet, (n, t) => n * (t.flags & TypeFlags.Union ? (<UnionType>t).types.length : 1), 1);
|
||||
if (size >= 100000) {
|
||||
error(currentNode, Diagnostics.Expression_produces_a_union_type_that_is_too_complex_to_represent);
|
||||
if (!checkCrossProductUnion(typeSet)) {
|
||||
return errorType;
|
||||
}
|
||||
const unionIndex = findIndex(typeSet, t => (t.flags & TypeFlags.Union) !== 0);
|
||||
@@ -13276,6 +13309,15 @@ namespace ts {
|
||||
return result;
|
||||
}
|
||||
|
||||
function checkCrossProductUnion(types: readonly Type[]) {
|
||||
const size = reduceLeft(types, (n, t) => n * (t.flags & TypeFlags.Union ? (<UnionType>t).types.length : t.flags & TypeFlags.Never ? 0 : 1), 1);
|
||||
if (size >= 100000) {
|
||||
error(currentNode, Diagnostics.Expression_produces_a_union_type_that_is_too_complex_to_represent);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
function getTypeFromIntersectionTypeNode(node: IntersectionTypeNode): Type {
|
||||
const links = getNodeLinks(node);
|
||||
if (!links.resolvedType) {
|
||||
@@ -13299,6 +13341,13 @@ namespace ts {
|
||||
type.resolvedIndexType || (type.resolvedIndexType = createIndexType(type, /*stringsOnly*/ false));
|
||||
}
|
||||
|
||||
function getIndexTypeForMappedType(type: MappedType, noIndexSignatures: boolean | undefined) {
|
||||
const constraint = filterType(getConstraintTypeFromMappedType(type), t => !(noIndexSignatures && t.flags & (TypeFlags.Any | TypeFlags.String)));
|
||||
return type.declaration.nameType ?
|
||||
instantiateType(getTypeFromTypeNode(type.declaration.nameType), appendTypeMapping(type.mapper, getTypeParameterFromMappedType(type), constraint)) :
|
||||
constraint;
|
||||
}
|
||||
|
||||
function getLiteralTypeFromPropertyName(name: PropertyName) {
|
||||
if (isPrivateIdentifier(name)) {
|
||||
return neverType;
|
||||
@@ -13347,7 +13396,7 @@ namespace ts {
|
||||
return type.flags & TypeFlags.Union ? getIntersectionType(map((<IntersectionType>type).types, t => getIndexType(t, stringsOnly, noIndexSignatures))) :
|
||||
type.flags & TypeFlags.Intersection ? getUnionType(map((<IntersectionType>type).types, t => getIndexType(t, stringsOnly, noIndexSignatures))) :
|
||||
type.flags & TypeFlags.InstantiableNonPrimitive || isGenericTupleType(type) ? getIndexTypeForGenericType(<InstantiableType | UnionOrIntersectionType>type, stringsOnly) :
|
||||
getObjectFlags(type) & ObjectFlags.Mapped ? filterType(getConstraintTypeFromMappedType(<MappedType>type), t => !(noIndexSignatures && t.flags & (TypeFlags.Any | TypeFlags.String))) :
|
||||
getObjectFlags(type) & ObjectFlags.Mapped ? getIndexTypeForMappedType(<MappedType>type, noIndexSignatures) :
|
||||
type === wildcardType ? wildcardType :
|
||||
type.flags & TypeFlags.Unknown ? neverType :
|
||||
type.flags & (TypeFlags.Any | TypeFlags.Never) ? keyofConstraintType :
|
||||
@@ -13392,6 +13441,83 @@ namespace ts {
|
||||
return links.resolvedType;
|
||||
}
|
||||
|
||||
function getTypeFromTemplateTypeNode(node: TemplateLiteralTypeNode) {
|
||||
const links = getNodeLinks(node);
|
||||
if (!links.resolvedType) {
|
||||
links.resolvedType = getTemplateLiteralType(
|
||||
[node.head.text, ...map(node.templateSpans, span => span.literal.text)],
|
||||
map(node.templateSpans, span => span.casing),
|
||||
map(node.templateSpans, span => getTypeFromTypeNode(span.type)));
|
||||
}
|
||||
return links.resolvedType;
|
||||
}
|
||||
|
||||
function getTemplateLiteralType(texts: readonly string[], casings: readonly TemplateCasing[], types: readonly Type[]): Type {
|
||||
const unionIndex = findIndex(types, t => !!(t.flags & (TypeFlags.Never | TypeFlags.Union)));
|
||||
if (unionIndex >= 0) {
|
||||
return checkCrossProductUnion(types) ?
|
||||
mapType(types[unionIndex], t => getTemplateLiteralType(texts, casings, replaceElement(types, unionIndex, t))) :
|
||||
errorType;
|
||||
}
|
||||
const newTypes = [];
|
||||
const newCasings = [];
|
||||
const newTexts = [];
|
||||
let text = texts[0];
|
||||
for (let i = 0; i < types.length; i++) {
|
||||
const t = types[i];
|
||||
if (t.flags & TypeFlags.Literal) {
|
||||
const s = applyTemplateCasing(getTemplateStringForType(t) || "", casings[i]);
|
||||
text += s;
|
||||
text += texts[i + 1];
|
||||
}
|
||||
else if (isGenericIndexType(t)) {
|
||||
newTypes.push(t);
|
||||
newCasings.push(casings[i]);
|
||||
newTexts.push(text);
|
||||
text = texts[i + 1];
|
||||
}
|
||||
else {
|
||||
return stringType;
|
||||
}
|
||||
}
|
||||
if (newTypes.length === 0) {
|
||||
return getLiteralType(text);
|
||||
}
|
||||
newTexts.push(text);
|
||||
const id = `${getTypeListId(newTypes)}|${newCasings.join(",")}|${map(newTexts, t => t.length).join(",")}|${newTexts.join("")}`;
|
||||
let type = templateLiteralTypes.get(id);
|
||||
if (!type) {
|
||||
templateLiteralTypes.set(id, type = createTemplateLiteralType(newTexts, newCasings, newTypes));
|
||||
}
|
||||
return type;
|
||||
}
|
||||
|
||||
function getTemplateStringForType(type: Type) {
|
||||
return type.flags & TypeFlags.StringLiteral ? (<StringLiteralType>type).value :
|
||||
type.flags & TypeFlags.NumberLiteral ? "" + (<NumberLiteralType>type).value :
|
||||
type.flags & TypeFlags.BigIntLiteral ? pseudoBigIntToString((<BigIntLiteralType>type).value) :
|
||||
type.flags & TypeFlags.BooleanLiteral ? (<IntrinsicType>type).intrinsicName :
|
||||
undefined;
|
||||
}
|
||||
|
||||
function applyTemplateCasing(str: string, casing: TemplateCasing) {
|
||||
switch (casing) {
|
||||
case TemplateCasing.Uppercase: return str.toUpperCase();
|
||||
case TemplateCasing.Lowercase: return str.toLowerCase();
|
||||
case TemplateCasing.Capitalize: return str.charAt(0).toUpperCase() + str.slice(1);
|
||||
case TemplateCasing.Uncapitalize: return str.charAt(0).toLowerCase() + str.slice(1);
|
||||
}
|
||||
return str;
|
||||
}
|
||||
|
||||
function createTemplateLiteralType(texts: readonly string[], casings: readonly TemplateCasing[], types: readonly Type[]) {
|
||||
const type = <TemplateLiteralType>createType(TypeFlags.TemplateLiteral);
|
||||
type.texts = texts;
|
||||
type.casings = casings;
|
||||
type.types = types;
|
||||
return type;
|
||||
}
|
||||
|
||||
function createIndexedAccessType(objectType: Type, indexType: Type, aliasSymbol: Symbol | undefined, aliasTypeArguments: readonly Type[] | undefined) {
|
||||
const type = <IndexedAccessType>createType(TypeFlags.IndexedAccess);
|
||||
type.objectType = objectType;
|
||||
@@ -13624,7 +13750,7 @@ namespace ts {
|
||||
}
|
||||
return !!((<UnionOrIntersectionType>type).objectFlags & ObjectFlags.IsGenericIndexType);
|
||||
}
|
||||
return !!(type.flags & (TypeFlags.InstantiableNonPrimitive | TypeFlags.Index));
|
||||
return !!(type.flags & (TypeFlags.InstantiableNonPrimitive | TypeFlags.Index | TypeFlags.TemplateLiteral));
|
||||
}
|
||||
|
||||
function isThisTypeParameter(type: Type): boolean {
|
||||
@@ -14122,7 +14248,7 @@ namespace ts {
|
||||
}
|
||||
|
||||
function isEmptyObjectTypeOrSpreadsIntoEmptyObject(type: Type) {
|
||||
return isEmptyObjectType(type) || !!(type.flags & (TypeFlags.Null | TypeFlags.Undefined | TypeFlags.BooleanLike | TypeFlags.NumberLike | TypeFlags.BigIntLike | TypeFlags.StringLike | TypeFlags.EnumLike | TypeFlags.NonPrimitive | TypeFlags.Index));
|
||||
return isEmptyObjectType(type) || !!(type.flags & (TypeFlags.Null | TypeFlags.Undefined | TypeFlags.BooleanLike | TypeFlags.NumberLike | TypeFlags.BigIntLike | TypeFlags.StringLike | TypeFlags.EnumLike | TypeFlags.NonPrimitive | TypeFlags.Index | TypeFlags.TemplateLiteral));
|
||||
}
|
||||
|
||||
function isSinglePropertyAnonymousObjectType(type: Type) {
|
||||
@@ -14208,7 +14334,7 @@ namespace ts {
|
||||
}
|
||||
return mapType(right, t => getSpreadType(left, t, symbol, objectFlags, readonly));
|
||||
}
|
||||
if (right.flags & (TypeFlags.BooleanLike | TypeFlags.NumberLike | TypeFlags.BigIntLike | TypeFlags.StringLike | TypeFlags.EnumLike | TypeFlags.NonPrimitive | TypeFlags.Index)) {
|
||||
if (right.flags & (TypeFlags.BooleanLike | TypeFlags.NumberLike | TypeFlags.BigIntLike | TypeFlags.StringLike | TypeFlags.EnumLike | TypeFlags.NonPrimitive | TypeFlags.Index | TypeFlags.TemplateLiteral)) {
|
||||
return left;
|
||||
}
|
||||
|
||||
@@ -14540,6 +14666,8 @@ namespace ts {
|
||||
return getTypeFromConditionalTypeNode(<ConditionalTypeNode>node);
|
||||
case SyntaxKind.InferType:
|
||||
return getTypeFromInferTypeNode(<InferTypeNode>node);
|
||||
case SyntaxKind.TemplateLiteralType:
|
||||
return getTypeFromTemplateTypeNode(<TemplateLiteralTypeNode>node);
|
||||
case SyntaxKind.ImportType:
|
||||
return getTypeFromImportTypeNode(<ImportTypeNode>node);
|
||||
// This function assumes that an identifier, qualified name, or property access expression is a type expression
|
||||
@@ -14837,13 +14965,18 @@ namespace ts {
|
||||
if (typeVariable !== mappedTypeVariable) {
|
||||
return mapType(getReducedType(mappedTypeVariable), t => {
|
||||
if (t.flags & (TypeFlags.AnyOrUnknown | TypeFlags.InstantiableNonPrimitive | TypeFlags.Object | TypeFlags.Intersection) && t !== wildcardType && t !== errorType) {
|
||||
if (isGenericTupleType(t)) {
|
||||
return instantiateMappedGenericTupleType(t, type, typeVariable, mapper);
|
||||
if (!type.declaration.nameType) {
|
||||
if (isArrayType(t)) {
|
||||
return instantiateMappedArrayType(t, type, prependTypeMapping(typeVariable, t, mapper));
|
||||
}
|
||||
if (isGenericTupleType(t)) {
|
||||
return instantiateMappedGenericTupleType(t, type, typeVariable, mapper);
|
||||
}
|
||||
if (isTupleType(t)) {
|
||||
return instantiateMappedTupleType(t, type, prependTypeMapping(typeVariable, t, mapper));
|
||||
}
|
||||
}
|
||||
const replacementMapper = prependTypeMapping(typeVariable, t, mapper);
|
||||
return isArrayType(t) ? instantiateMappedArrayType(t, type, replacementMapper) :
|
||||
isTupleType(t) ? instantiateMappedTupleType(t, type, replacementMapper) :
|
||||
instantiateAnonymousType(type, replacementMapper);
|
||||
return instantiateAnonymousType(type, prependTypeMapping(typeVariable, t, mapper));
|
||||
}
|
||||
return t;
|
||||
});
|
||||
@@ -15001,6 +15134,9 @@ namespace ts {
|
||||
if (flags & TypeFlags.Index) {
|
||||
return getIndexType(instantiateType((<IndexType>type).type, mapper));
|
||||
}
|
||||
if (flags & TypeFlags.TemplateLiteral) {
|
||||
return getTemplateLiteralType((<TemplateLiteralType>type).texts, (<TemplateLiteralType>type).casings, instantiateTypes((<TemplateLiteralType>type).types, mapper));
|
||||
}
|
||||
if (flags & TypeFlags.IndexedAccess) {
|
||||
return getIndexedAccessType(instantiateType((<IndexedAccessType>type).objectType, mapper), instantiateType((<IndexedAccessType>type).indexType, mapper), /*accessNode*/ undefined, type.aliasSymbol, instantiateTypes(type.aliasTypeArguments, mapper));
|
||||
}
|
||||
@@ -16987,7 +17123,8 @@ namespace ts {
|
||||
|
||||
if (target.flags & TypeFlags.TypeParameter) {
|
||||
// A source type { [P in Q]: X } is related to a target type T if keyof T is related to Q and X is related to T[Q].
|
||||
if (getObjectFlags(source) & ObjectFlags.Mapped && isRelatedTo(getIndexType(target), getConstraintTypeFromMappedType(<MappedType>source))) {
|
||||
if (getObjectFlags(source) & ObjectFlags.Mapped && !(<MappedType>source).declaration.nameType && isRelatedTo(getIndexType(target), getConstraintTypeFromMappedType(<MappedType>source))) {
|
||||
|
||||
if (!(getMappedTypeModifiers(<MappedType>source) & MappedTypeModifiers.IncludeOptional)) {
|
||||
const templateType = getTemplateTypeFromMappedType(<MappedType>source);
|
||||
const indexedAccessType = getIndexedAccessType(target, getTypeParameterFromMappedType(<MappedType>source));
|
||||
@@ -17044,7 +17181,7 @@ namespace ts {
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (isGenericMappedType(target)) {
|
||||
else if (isGenericMappedType(target) && !target.declaration.nameType) {
|
||||
// A source type T is related to a target type { [P in X]: T[P] }
|
||||
const template = getTemplateTypeFromMappedType(target);
|
||||
const modifiers = getMappedTypeModifiers(target);
|
||||
@@ -17126,6 +17263,13 @@ namespace ts {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
else if (source.flags & TypeFlags.TemplateLiteral) {
|
||||
const constraint = getBaseConstraintOfType(source);
|
||||
if (constraint && (result = isRelatedTo(constraint, target, reportErrors))) {
|
||||
resetErrorInfo(saveErrorInfo);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
else if (source.flags & TypeFlags.Conditional) {
|
||||
if (target.flags & TypeFlags.Conditional) {
|
||||
// Two conditional types 'T1 extends U1 ? X1 : Y1' and 'T2 extends U2 ? X2 : Y2' are related if
|
||||
@@ -17339,7 +17483,9 @@ namespace ts {
|
||||
const sourceConstraint = instantiateType(getConstraintTypeFromMappedType(source), makeFunctionTypeMapper(getCombinedMappedTypeOptionality(source) < 0 ? reportUnmeasurableMarkers : reportUnreliableMarkers));
|
||||
if (result = isRelatedTo(targetConstraint, sourceConstraint, reportErrors)) {
|
||||
const mapper = createTypeMapper([getTypeParameterFromMappedType(source)], [getTypeParameterFromMappedType(target)]);
|
||||
return result & isRelatedTo(instantiateType(getTemplateTypeFromMappedType(source), mapper), getTemplateTypeFromMappedType(target), reportErrors);
|
||||
if (instantiateType(getNameTypeFromMappedType(source), mapper) === instantiateType(getNameTypeFromMappedType(target), mapper)) {
|
||||
return result & isRelatedTo(instantiateType(getTemplateTypeFromMappedType(source), mapper), getTemplateTypeFromMappedType(target), reportErrors);
|
||||
}
|
||||
}
|
||||
}
|
||||
return Ternary.False;
|
||||
@@ -19575,6 +19721,9 @@ namespace ts {
|
||||
inferFromTypes(sourceType, target);
|
||||
}
|
||||
}
|
||||
else if (target.flags & TypeFlags.TemplateLiteral) {
|
||||
inferToTemplateLiteralType(source, <TemplateLiteralType>target);
|
||||
}
|
||||
else {
|
||||
source = getReducedType(source);
|
||||
if (!(priority & InferencePriority.NoConstraints && source.flags & (TypeFlags.Intersection | TypeFlags.Instantiable))) {
|
||||
@@ -19627,8 +19776,8 @@ namespace ts {
|
||||
// We stop inferring and report a circularity if we encounter duplicate recursion identities on both
|
||||
// the source side and the target side.
|
||||
const saveExpandingFlags = expandingFlags;
|
||||
const sourceIdentity = getRecursionIdentity(source);
|
||||
const targetIdentity = getRecursionIdentity(target);
|
||||
const sourceIdentity = getRecursionIdentity(source) || source;
|
||||
const targetIdentity = getRecursionIdentity(target) || target;
|
||||
if (sourceIdentity && contains(sourceStack, sourceIdentity)) expandingFlags |= ExpandingFlags.Source;
|
||||
if (targetIdentity && contains(targetStack, targetIdentity)) expandingFlags |= ExpandingFlags.Target;
|
||||
if (expandingFlags !== ExpandingFlags.Both) {
|
||||
@@ -19853,6 +20002,39 @@ namespace ts {
|
||||
}
|
||||
}
|
||||
|
||||
function inferToTemplateLiteralType(source: Type, target: TemplateLiteralType) {
|
||||
if (source.flags & (TypeFlags.StringLike | TypeFlags.Index)) {
|
||||
const matches = source.flags & TypeFlags.StringLiteral ? inferLiteralsFromTemplateLiteralType(<StringLiteralType>source, target) :
|
||||
source.flags & TypeFlags.TemplateLiteral && arraysEqual((<TemplateLiteralType>source).texts, target.texts) && arraysEqual((<TemplateLiteralType>source).casings, target.casings)? (<TemplateLiteralType>source).types :
|
||||
undefined;
|
||||
const types = target.types;
|
||||
for (let i = 0; i < types.length; i++) {
|
||||
inferFromTypes(matches ? matches[i] : source.flags & TypeFlags.StringLiteral ? neverType : stringType, types[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function inferLiteralsFromTemplateLiteralType(source: StringLiteralType, target: TemplateLiteralType): Type[] | undefined {
|
||||
const value = source.value;
|
||||
const texts = target.texts;
|
||||
const lastIndex = texts.length - 1;
|
||||
const startText = texts[0];
|
||||
const endText = texts[lastIndex];
|
||||
if (!(value.startsWith(startText) && value.endsWith(endText))) return undefined;
|
||||
const matches = [];
|
||||
const str = value.slice(startText.length, value.length - endText.length);
|
||||
let pos = 0;
|
||||
for (let i = 1; i < lastIndex; i++) {
|
||||
const delim = texts[i];
|
||||
const delimPos = delim.length > 0 ? str.indexOf(delim, pos) : pos < str.length ? pos + 1 : -1;
|
||||
if (delimPos < 0) return undefined;
|
||||
matches.push(getLiteralType(str.slice(pos, delimPos)));
|
||||
pos = delimPos + delim.length;
|
||||
}
|
||||
matches.push(getLiteralType(str.slice(pos)));
|
||||
return matches;
|
||||
}
|
||||
|
||||
function inferFromObjectTypes(source: Type, target: Type) {
|
||||
if (getObjectFlags(source) & ObjectFlags.Reference && getObjectFlags(target) & ObjectFlags.Reference && (
|
||||
(<TypeReference>source).target === (<TypeReference>target).target || isArrayType(source) && isArrayType(target))) {
|
||||
@@ -19865,8 +20047,11 @@ namespace ts {
|
||||
// from S to T and from X to Y.
|
||||
inferFromTypes(getConstraintTypeFromMappedType(source), getConstraintTypeFromMappedType(target));
|
||||
inferFromTypes(getTemplateTypeFromMappedType(source), getTemplateTypeFromMappedType(target));
|
||||
const sourceNameType = getNameTypeFromMappedType(source);
|
||||
const targetNameType = getNameTypeFromMappedType(target);
|
||||
if (sourceNameType && targetNameType) inferFromTypes(sourceNameType, targetNameType);
|
||||
}
|
||||
if (getObjectFlags(target) & ObjectFlags.Mapped) {
|
||||
if (getObjectFlags(target) & ObjectFlags.Mapped && !(<MappedType>target).declaration.nameType) {
|
||||
const constraintType = getConstraintTypeFromMappedType(<MappedType>target);
|
||||
if (inferToMappedType(source, <MappedType>target, constraintType)) {
|
||||
return;
|
||||
@@ -20015,7 +20200,7 @@ namespace ts {
|
||||
|
||||
function hasPrimitiveConstraint(type: TypeParameter): boolean {
|
||||
const constraint = getConstraintOfTypeParameter(type);
|
||||
return !!constraint && maybeTypeOfKind(constraint.flags & TypeFlags.Conditional ? getDefaultConstraintOfConditionalType(constraint as ConditionalType) : constraint, TypeFlags.Primitive | TypeFlags.Index);
|
||||
return !!constraint && maybeTypeOfKind(constraint.flags & TypeFlags.Conditional ? getDefaultConstraintOfConditionalType(constraint as ConditionalType) : constraint, TypeFlags.Primitive | TypeFlags.Index | TypeFlags.TemplateLiteral);
|
||||
}
|
||||
|
||||
function isObjectLiteralType(type: Type) {
|
||||
@@ -26059,7 +26244,7 @@ namespace ts {
|
||||
else {
|
||||
const contextualType = getIndexedAccessType(restType, getLiteralType(i - index));
|
||||
const argType = checkExpressionWithContextualType(arg, contextualType, context, checkMode);
|
||||
const hasPrimitiveContextualType = maybeTypeOfKind(contextualType, TypeFlags.Primitive | TypeFlags.Index);
|
||||
const hasPrimitiveContextualType = maybeTypeOfKind(contextualType, TypeFlags.Primitive | TypeFlags.Index | TypeFlags.TemplateLiteral);
|
||||
types.push(hasPrimitiveContextualType ? getRegularTypeOfLiteralType(argType) : getWidenedLiteralType(argType));
|
||||
flags.push(ElementFlags.Required);
|
||||
}
|
||||
@@ -29098,7 +29283,7 @@ namespace ts {
|
||||
// and the right operand to be of type Any, an object type, or a type parameter type.
|
||||
// The result is always of the Boolean primitive type.
|
||||
if (!(allTypesAssignableToKind(leftType, TypeFlags.StringLike | TypeFlags.NumberLike | TypeFlags.ESSymbolLike) ||
|
||||
isTypeAssignableToKind(leftType, TypeFlags.Index | TypeFlags.TypeParameter))) {
|
||||
isTypeAssignableToKind(leftType, TypeFlags.Index | TypeFlags.TemplateLiteral | TypeFlags.TypeParameter))) {
|
||||
error(left, Diagnostics.The_left_hand_side_of_an_in_expression_must_be_of_type_any_string_number_or_symbol);
|
||||
}
|
||||
if (!allTypesAssignableToKind(rightType, TypeFlags.NonPrimitive | TypeFlags.InstantiableNonPrimitive)) {
|
||||
@@ -30047,7 +30232,7 @@ namespace ts {
|
||||
}
|
||||
// If the contextual type is a literal of a particular primitive type, we consider this a
|
||||
// literal context for all literals of that primitive type.
|
||||
return !!(contextualType.flags & (TypeFlags.StringLiteral | TypeFlags.Index) && maybeTypeOfKind(candidateType, TypeFlags.StringLiteral) ||
|
||||
return !!(contextualType.flags & (TypeFlags.StringLiteral | TypeFlags.Index | TypeFlags.TemplateLiteral) && maybeTypeOfKind(candidateType, TypeFlags.StringLiteral) ||
|
||||
contextualType.flags & TypeFlags.NumberLiteral && maybeTypeOfKind(candidateType, TypeFlags.NumberLiteral) ||
|
||||
contextualType.flags & TypeFlags.BigIntLiteral && maybeTypeOfKind(candidateType, TypeFlags.BigIntLiteral) ||
|
||||
contextualType.flags & TypeFlags.BooleanLiteral && maybeTypeOfKind(candidateType, TypeFlags.BooleanLiteral) ||
|
||||
@@ -31206,10 +31391,12 @@ namespace ts {
|
||||
}
|
||||
}
|
||||
forEach(node.elements, checkSourceElement);
|
||||
getTypeFromTypeNode(node);
|
||||
}
|
||||
|
||||
function checkUnionOrIntersectionType(node: UnionOrIntersectionTypeNode) {
|
||||
forEach(node.types, checkSourceElement);
|
||||
getTypeFromTypeNode(node);
|
||||
}
|
||||
|
||||
function checkIndexedAccessIndexType(type: Type, accessNode: IndexedAccessTypeNode | ElementAccessExpression) {
|
||||
@@ -31254,6 +31441,7 @@ namespace ts {
|
||||
|
||||
function checkMappedType(node: MappedTypeNode) {
|
||||
checkSourceElement(node.typeParameter);
|
||||
checkSourceElement(node.nameType);
|
||||
checkSourceElement(node.type);
|
||||
|
||||
if (!node.type) {
|
||||
@@ -31261,8 +31449,14 @@ namespace ts {
|
||||
}
|
||||
|
||||
const type = <MappedType>getTypeFromMappedTypeNode(node);
|
||||
const constraintType = getConstraintTypeFromMappedType(type);
|
||||
checkTypeAssignableTo(constraintType, keyofConstraintType, getEffectiveConstraintOfTypeParameter(node.typeParameter));
|
||||
const nameType = getNameTypeFromMappedType(type);
|
||||
if (nameType) {
|
||||
checkTypeAssignableTo(nameType, keyofConstraintType, node.nameType);
|
||||
}
|
||||
else {
|
||||
const constraintType = getConstraintTypeFromMappedType(type);
|
||||
checkTypeAssignableTo(constraintType, keyofConstraintType, getEffectiveConstraintOfTypeParameter(node.typeParameter));
|
||||
}
|
||||
}
|
||||
|
||||
function checkThisType(node: ThisTypeNode) {
|
||||
@@ -31286,6 +31480,18 @@ namespace ts {
|
||||
registerForUnusedIdentifiersCheck(node);
|
||||
}
|
||||
|
||||
function checkTemplateType(node: TemplateLiteralTypeNode) {
|
||||
forEachChild(node, checkSourceElement);
|
||||
getTypeFromTypeNode(node);
|
||||
for (const span of node.templateSpans) {
|
||||
const type = getTypeFromTypeNode(span.type);
|
||||
checkTypeAssignableTo(type, templateConstraintType, span.type);
|
||||
if (!everyType(type, t => !!(t.flags & TypeFlags.Literal) || isGenericIndexType(t))) {
|
||||
error(span.type, Diagnostics.Template_literal_type_argument_0_is_not_literal_type_or_a_generic_type, typeToString(type));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function checkImportType(node: ImportTypeNode) {
|
||||
checkSourceElement(node.argument);
|
||||
getTypeFromTypeNode(node);
|
||||
@@ -35897,6 +36103,8 @@ namespace ts {
|
||||
return checkConditionalType(<ConditionalTypeNode>node);
|
||||
case SyntaxKind.InferType:
|
||||
return checkInferType(<InferTypeNode>node);
|
||||
case SyntaxKind.TemplateLiteralType:
|
||||
return checkTemplateType(<TemplateLiteralTypeNode>node);
|
||||
case SyntaxKind.ImportType:
|
||||
return checkImportType(<ImportTypeNode>node);
|
||||
case SyntaxKind.NamedTupleMember:
|
||||
|
||||
@@ -3028,6 +3028,10 @@
|
||||
"category": "Error",
|
||||
"code": 2792
|
||||
},
|
||||
"Template literal type argument '{0}' is not literal type or a generic type.": {
|
||||
"category": "Error",
|
||||
"code": 2793
|
||||
},
|
||||
|
||||
"Import declaration '{0}' is using private name '{1}'.": {
|
||||
"category": "Error",
|
||||
|
||||
@@ -1313,6 +1313,8 @@ namespace ts {
|
||||
return emitConstructSignature(<ConstructSignatureDeclaration>node);
|
||||
case SyntaxKind.IndexSignature:
|
||||
return emitIndexSignature(<IndexSignatureDeclaration>node);
|
||||
case SyntaxKind.TemplateLiteralTypeSpan:
|
||||
return emitTemplateTypeSpan(<TemplateLiteralTypeSpan>node);
|
||||
|
||||
// Types
|
||||
case SyntaxKind.TypePredicate:
|
||||
@@ -1357,6 +1359,8 @@ namespace ts {
|
||||
return emitMappedType(<MappedTypeNode>node);
|
||||
case SyntaxKind.LiteralType:
|
||||
return emitLiteralType(<LiteralTypeNode>node);
|
||||
case SyntaxKind.TemplateLiteralType:
|
||||
return emitTemplateType(<TemplateLiteralTypeNode>node);
|
||||
case SyntaxKind.ImportType:
|
||||
return emitImportTypeNode(<ImportTypeNode>node);
|
||||
case SyntaxKind.JSDocAllType:
|
||||
@@ -2010,6 +2014,20 @@ namespace ts {
|
||||
writeTrailingSemicolon();
|
||||
}
|
||||
|
||||
function emitTemplateTypeSpan(node: TemplateLiteralTypeSpan) {
|
||||
const keyword = node.casing === TemplateCasing.Uppercase ? "uppercase" :
|
||||
node.casing === TemplateCasing.Lowercase ? "lowercase" :
|
||||
node.casing === TemplateCasing.Capitalize ? "capitalize" :
|
||||
node.casing === TemplateCasing.Uncapitalize ? "uncapitalize" :
|
||||
undefined;
|
||||
if (keyword) {
|
||||
writeKeyword(keyword);
|
||||
writeSpace();
|
||||
}
|
||||
emit(node.type);
|
||||
emit(node.literal);
|
||||
}
|
||||
|
||||
function emitSemicolonClassElement() {
|
||||
writeTrailingSemicolon();
|
||||
}
|
||||
@@ -2202,6 +2220,12 @@ namespace ts {
|
||||
writePunctuation("[");
|
||||
|
||||
pipelineEmit(EmitHint.MappedTypeParameter, node.typeParameter);
|
||||
if (node.nameType) {
|
||||
writeSpace();
|
||||
writeKeyword("as");
|
||||
writeSpace();
|
||||
emit(node.nameType);
|
||||
}
|
||||
|
||||
writePunctuation("]");
|
||||
if (node.questionToken) {
|
||||
@@ -2228,6 +2252,11 @@ namespace ts {
|
||||
emitExpression(node.literal);
|
||||
}
|
||||
|
||||
function emitTemplateType(node: TemplateLiteralTypeNode) {
|
||||
emit(node.head);
|
||||
emitList(node, node.templateSpans, ListFormat.TemplateExpressionSpans);
|
||||
}
|
||||
|
||||
function emitImportTypeNode(node: ImportTypeNode) {
|
||||
if (node.isTypeOf) {
|
||||
writeKeyword("typeof");
|
||||
|
||||
@@ -94,6 +94,8 @@ namespace ts {
|
||||
updateConstructSignature,
|
||||
createIndexSignature,
|
||||
updateIndexSignature,
|
||||
createTemplateLiteralTypeSpan,
|
||||
updateTemplateLiteralTypeSpan,
|
||||
createKeywordTypeNode,
|
||||
createTypePredicateNode,
|
||||
updateTypePredicateNode,
|
||||
@@ -138,6 +140,8 @@ namespace ts {
|
||||
updateMappedTypeNode,
|
||||
createLiteralTypeNode,
|
||||
updateLiteralTypeNode,
|
||||
createTemplateLiteralType,
|
||||
updateTemplateLiteralType,
|
||||
createObjectBindingPattern,
|
||||
updateObjectBindingPattern,
|
||||
createArrayBindingPattern,
|
||||
@@ -1600,6 +1604,25 @@ namespace ts {
|
||||
: node;
|
||||
}
|
||||
|
||||
// @api
|
||||
function createTemplateLiteralTypeSpan(casing: TemplateCasing, type: TypeNode, literal: TemplateMiddle | TemplateTail) {
|
||||
const node = createBaseNode<TemplateLiteralTypeSpan>(SyntaxKind.TemplateLiteralTypeSpan);
|
||||
node.casing = casing;
|
||||
node.type = type;
|
||||
node.literal = literal;
|
||||
node.transformFlags = TransformFlags.ContainsTypeScript;
|
||||
return node;
|
||||
}
|
||||
|
||||
// @api
|
||||
function updateTemplateLiteralTypeSpan(casing: TemplateCasing, node: TemplateLiteralTypeSpan, type: TypeNode, literal: TemplateMiddle | TemplateTail) {
|
||||
return node.casing !== casing
|
||||
|| node.type !== type
|
||||
|| node.literal !== literal
|
||||
? update(createTemplateLiteralTypeSpan(casing, type, literal), node)
|
||||
: node;
|
||||
}
|
||||
|
||||
//
|
||||
// Types
|
||||
//
|
||||
@@ -1891,6 +1914,23 @@ namespace ts {
|
||||
: node;
|
||||
}
|
||||
|
||||
// @api
|
||||
function createTemplateLiteralType(head: TemplateHead, templateSpans: readonly TemplateLiteralTypeSpan[]) {
|
||||
const node = createBaseNode<TemplateLiteralTypeNode>(SyntaxKind.TemplateLiteralType);
|
||||
node.head = head;
|
||||
node.templateSpans = createNodeArray(templateSpans);
|
||||
node.transformFlags = TransformFlags.ContainsTypeScript;
|
||||
return node;
|
||||
}
|
||||
|
||||
// @api
|
||||
function updateTemplateLiteralType(node: TemplateLiteralTypeNode, head: TemplateHead, templateSpans: readonly TemplateLiteralTypeSpan[]) {
|
||||
return node.head !== head
|
||||
|| node.templateSpans !== templateSpans
|
||||
? update(createTemplateLiteralType(head, templateSpans), node)
|
||||
: node;
|
||||
}
|
||||
|
||||
// @api
|
||||
function createImportTypeNode(argument: TypeNode, qualifier?: EntityName, typeArguments?: readonly TypeNode[], isTypeOf = false) {
|
||||
const node = createBaseNode<ImportTypeNode>(SyntaxKind.ImportType);
|
||||
@@ -1968,10 +2008,11 @@ namespace ts {
|
||||
}
|
||||
|
||||
// @api
|
||||
function createMappedTypeNode(readonlyToken: ReadonlyKeyword | PlusToken | MinusToken | undefined, typeParameter: TypeParameterDeclaration, questionToken: QuestionToken | PlusToken | MinusToken | undefined, type: TypeNode | undefined): MappedTypeNode {
|
||||
function createMappedTypeNode(readonlyToken: ReadonlyKeyword | PlusToken | MinusToken | undefined, typeParameter: TypeParameterDeclaration, nameType: TypeNode | undefined, questionToken: QuestionToken | PlusToken | MinusToken | undefined, type: TypeNode | undefined): MappedTypeNode {
|
||||
const node = createBaseNode<MappedTypeNode>(SyntaxKind.MappedType);
|
||||
node.readonlyToken = readonlyToken;
|
||||
node.typeParameter = typeParameter;
|
||||
node.nameType = nameType;
|
||||
node.questionToken = questionToken;
|
||||
node.type = type;
|
||||
node.transformFlags = TransformFlags.ContainsTypeScript;
|
||||
@@ -1979,12 +2020,13 @@ namespace ts {
|
||||
}
|
||||
|
||||
// @api
|
||||
function updateMappedTypeNode(node: MappedTypeNode, readonlyToken: ReadonlyKeyword | PlusToken | MinusToken | undefined, typeParameter: TypeParameterDeclaration, questionToken: QuestionToken | PlusToken | MinusToken | undefined, type: TypeNode | undefined): MappedTypeNode {
|
||||
function updateMappedTypeNode(node: MappedTypeNode, readonlyToken: ReadonlyKeyword | PlusToken | MinusToken | undefined, typeParameter: TypeParameterDeclaration, nameType: TypeNode | undefined, questionToken: QuestionToken | PlusToken | MinusToken | undefined, type: TypeNode | undefined): MappedTypeNode {
|
||||
return node.readonlyToken !== readonlyToken
|
||||
|| node.typeParameter !== typeParameter
|
||||
|| node.nameType !== nameType
|
||||
|| node.questionToken !== questionToken
|
||||
|| node.type !== type
|
||||
? update(createMappedTypeNode(readonlyToken, typeParameter, questionToken, type), node)
|
||||
? update(createMappedTypeNode(readonlyToken, typeParameter, nameType, questionToken, type), node)
|
||||
: node;
|
||||
}
|
||||
|
||||
|
||||
+54
-1
@@ -206,6 +206,7 @@ namespace ts {
|
||||
case SyntaxKind.MappedType:
|
||||
return visitNode(cbNode, (<MappedTypeNode>node).readonlyToken) ||
|
||||
visitNode(cbNode, (<MappedTypeNode>node).typeParameter) ||
|
||||
visitNode(cbNode, (<MappedTypeNode>node).nameType) ||
|
||||
visitNode(cbNode, (<MappedTypeNode>node).questionToken) ||
|
||||
visitNode(cbNode, (<MappedTypeNode>node).type);
|
||||
case SyntaxKind.LiteralType:
|
||||
@@ -424,6 +425,10 @@ namespace ts {
|
||||
return visitNode(cbNode, (<TemplateExpression>node).head) || visitNodes(cbNode, cbNodes, (<TemplateExpression>node).templateSpans);
|
||||
case SyntaxKind.TemplateSpan:
|
||||
return visitNode(cbNode, (<TemplateSpan>node).expression) || visitNode(cbNode, (<TemplateSpan>node).literal);
|
||||
case SyntaxKind.TemplateLiteralType:
|
||||
return visitNode(cbNode, (<TemplateLiteralTypeNode>node).head) || visitNodes(cbNode, cbNodes, (<TemplateLiteralTypeNode>node).templateSpans);
|
||||
case SyntaxKind.TemplateLiteralTypeSpan:
|
||||
return visitNode(cbNode, (<TemplateLiteralTypeSpan>node).type) || visitNode(cbNode, (<TemplateLiteralTypeSpan>node).literal);
|
||||
case SyntaxKind.ComputedPropertyName:
|
||||
return visitNode(cbNode, (<ComputedPropertyName>node).expression);
|
||||
case SyntaxKind.HeritageClause:
|
||||
@@ -2584,6 +2589,49 @@ namespace ts {
|
||||
);
|
||||
}
|
||||
|
||||
function parseTemplateType(): TemplateLiteralTypeNode {
|
||||
const pos = getNodePos();
|
||||
return finishNode(
|
||||
factory.createTemplateLiteralType(
|
||||
parseTemplateHead(/*isTaggedTemplate*/ false),
|
||||
parseTemplateTypeSpans()
|
||||
),
|
||||
pos
|
||||
);
|
||||
}
|
||||
|
||||
function parseTemplateTypeSpans() {
|
||||
const pos = getNodePos();
|
||||
const list = [];
|
||||
let node: TemplateLiteralTypeSpan;
|
||||
do {
|
||||
node = parseTemplateTypeSpan();
|
||||
list.push(node);
|
||||
}
|
||||
while (node.literal.kind === SyntaxKind.TemplateMiddle);
|
||||
return createNodeArray(list, pos);
|
||||
}
|
||||
|
||||
function parseTemplateTypeSpan(): TemplateLiteralTypeSpan {
|
||||
const pos = getNodePos();
|
||||
return finishNode(
|
||||
factory.createTemplateLiteralTypeSpan(
|
||||
parseTemplateCasing(),
|
||||
parseType(),
|
||||
parseLiteralOfTemplateSpan(/*isTaggedTemplate*/ false)
|
||||
),
|
||||
pos
|
||||
);
|
||||
}
|
||||
|
||||
function parseTemplateCasing(): TemplateCasing {
|
||||
return parseOptional(SyntaxKind.UppercaseKeyword) ? TemplateCasing.Uppercase :
|
||||
parseOptional(SyntaxKind.LowercaseKeyword) ? TemplateCasing.Lowercase :
|
||||
parseOptional(SyntaxKind.CapitalizeKeyword) ? TemplateCasing.Capitalize :
|
||||
parseOptional(SyntaxKind.UncapitalizeKeyword) ? TemplateCasing.Uncapitalize :
|
||||
TemplateCasing.None;
|
||||
}
|
||||
|
||||
function parseLiteralOfTemplateSpan(isTaggedTemplate: boolean) {
|
||||
if (token() === SyntaxKind.CloseBraceToken) {
|
||||
reScanTemplateToken(isTaggedTemplate);
|
||||
@@ -3252,6 +3300,7 @@ namespace ts {
|
||||
}
|
||||
parseExpected(SyntaxKind.OpenBracketToken);
|
||||
const typeParameter = parseMappedTypeParameter();
|
||||
const nameType = parseOptional(SyntaxKind.AsKeyword) ? parseType() : undefined;
|
||||
parseExpected(SyntaxKind.CloseBracketToken);
|
||||
let questionToken: QuestionToken | PlusToken | MinusToken | undefined;
|
||||
if (token() === SyntaxKind.QuestionToken || token() === SyntaxKind.PlusToken || token() === SyntaxKind.MinusToken) {
|
||||
@@ -3263,7 +3312,7 @@ namespace ts {
|
||||
const type = parseTypeAnnotation();
|
||||
parseSemicolon();
|
||||
parseExpected(SyntaxKind.CloseBraceToken);
|
||||
return finishNode(factory.createMappedTypeNode(readonlyToken, typeParameter, questionToken, type), pos);
|
||||
return finishNode(factory.createMappedTypeNode(readonlyToken, typeParameter, nameType, questionToken, type), pos);
|
||||
}
|
||||
|
||||
function parseTupleElementType() {
|
||||
@@ -3444,6 +3493,8 @@ namespace ts {
|
||||
return parseImportType();
|
||||
case SyntaxKind.AssertsKeyword:
|
||||
return lookAhead(nextTokenIsIdentifierOrKeywordOnSameLine) ? parseAssertsTypePredicate() : parseTypeReference();
|
||||
case SyntaxKind.TemplateHead:
|
||||
return parseTemplateType();
|
||||
default:
|
||||
return parseTypeReference();
|
||||
}
|
||||
@@ -3485,6 +3536,8 @@ namespace ts {
|
||||
case SyntaxKind.InferKeyword:
|
||||
case SyntaxKind.ImportKeyword:
|
||||
case SyntaxKind.AssertsKeyword:
|
||||
case SyntaxKind.NoSubstitutionTemplateLiteral:
|
||||
case SyntaxKind.TemplateHead:
|
||||
return true;
|
||||
case SyntaxKind.FunctionKeyword:
|
||||
return !inStartOfParameter;
|
||||
|
||||
@@ -151,6 +151,10 @@ namespace ts {
|
||||
yield: SyntaxKind.YieldKeyword,
|
||||
async: SyntaxKind.AsyncKeyword,
|
||||
await: SyntaxKind.AwaitKeyword,
|
||||
uppercase: SyntaxKind.UppercaseKeyword,
|
||||
lowercase: SyntaxKind.LowercaseKeyword,
|
||||
capitalize: SyntaxKind.CapitalizeKeyword,
|
||||
uncapitalize: SyntaxKind.UncapitalizeKeyword,
|
||||
of: SyntaxKind.OfKeyword,
|
||||
};
|
||||
|
||||
@@ -1508,9 +1512,9 @@ namespace ts {
|
||||
}
|
||||
|
||||
function getIdentifierToken(): SyntaxKind.Identifier | KeywordSyntaxKind {
|
||||
// Reserved words are between 2 and 11 characters long and start with a lowercase letter
|
||||
// Reserved words are between 2 and 12 characters long and start with a lowercase letter
|
||||
const len = tokenValue.length;
|
||||
if (len >= 2 && len <= 11) {
|
||||
if (len >= 2 && len <= 12) {
|
||||
const ch = tokenValue.charCodeAt(0);
|
||||
if (ch >= CharacterCodes.a && ch <= CharacterCodes.z) {
|
||||
const keyword = textToKeyword.get(tokenValue);
|
||||
|
||||
+56
-9
@@ -186,6 +186,10 @@ namespace ts {
|
||||
FromKeyword,
|
||||
GlobalKeyword,
|
||||
BigIntKeyword,
|
||||
UppercaseKeyword,
|
||||
LowercaseKeyword,
|
||||
CapitalizeKeyword,
|
||||
UncapitalizeKeyword,
|
||||
OfKeyword, // LastKeyword and LastToken and LastContextualKeyword
|
||||
|
||||
// Parse tree nodes
|
||||
@@ -230,6 +234,8 @@ namespace ts {
|
||||
MappedType,
|
||||
LiteralType,
|
||||
NamedTupleMember,
|
||||
TemplateLiteralType,
|
||||
TemplateLiteralTypeSpan,
|
||||
ImportType,
|
||||
// Binding patterns
|
||||
ObjectBindingPattern,
|
||||
@@ -538,6 +544,7 @@ namespace ts {
|
||||
| SyntaxKind.BigIntKeyword
|
||||
| SyntaxKind.BooleanKeyword
|
||||
| SyntaxKind.BreakKeyword
|
||||
| SyntaxKind.CapitalizeKeyword
|
||||
| SyntaxKind.CaseKeyword
|
||||
| SyntaxKind.CatchKeyword
|
||||
| SyntaxKind.ClassKeyword
|
||||
@@ -570,6 +577,7 @@ namespace ts {
|
||||
| SyntaxKind.IsKeyword
|
||||
| SyntaxKind.KeyOfKeyword
|
||||
| SyntaxKind.LetKeyword
|
||||
| SyntaxKind.LowercaseKeyword
|
||||
| SyntaxKind.ModuleKeyword
|
||||
| SyntaxKind.NamespaceKeyword
|
||||
| SyntaxKind.NeverKeyword
|
||||
@@ -597,9 +605,11 @@ namespace ts {
|
||||
| SyntaxKind.TryKeyword
|
||||
| SyntaxKind.TypeKeyword
|
||||
| SyntaxKind.TypeOfKeyword
|
||||
| SyntaxKind.UncapitalizeKeyword
|
||||
| SyntaxKind.UndefinedKeyword
|
||||
| SyntaxKind.UniqueKeyword
|
||||
| SyntaxKind.UnknownKeyword
|
||||
| SyntaxKind.UppercaseKeyword
|
||||
| SyntaxKind.VarKeyword
|
||||
| SyntaxKind.VoidKeyword
|
||||
| SyntaxKind.WhileKeyword
|
||||
@@ -659,6 +669,8 @@ namespace ts {
|
||||
| SyntaxKind.IndexedAccessType
|
||||
| SyntaxKind.MappedType
|
||||
| SyntaxKind.LiteralType
|
||||
| SyntaxKind.TemplateLiteralType
|
||||
| SyntaxKind.TemplateLiteralTypeSpan
|
||||
| SyntaxKind.ImportType
|
||||
| SyntaxKind.ExpressionWithTypeArguments
|
||||
| SyntaxKind.JSDocTypeExpression
|
||||
@@ -1622,6 +1634,7 @@ namespace ts {
|
||||
readonly kind: SyntaxKind.MappedType;
|
||||
readonly readonlyToken?: ReadonlyToken | PlusToken | MinusToken;
|
||||
readonly typeParameter: TypeParameterDeclaration;
|
||||
readonly nameType?: TypeNode;
|
||||
readonly questionToken?: QuestionToken | PlusToken | MinusToken;
|
||||
readonly type?: TypeNode;
|
||||
}
|
||||
@@ -1641,6 +1654,28 @@ namespace ts {
|
||||
export type StringLiteralLike = StringLiteral | NoSubstitutionTemplateLiteral;
|
||||
export type PropertyNameLiteral = Identifier | StringLiteralLike | NumericLiteral;
|
||||
|
||||
export interface TemplateLiteralTypeNode extends TypeNode {
|
||||
kind: SyntaxKind.TemplateLiteralType,
|
||||
readonly head: TemplateHead;
|
||||
readonly templateSpans: NodeArray<TemplateLiteralTypeSpan>;
|
||||
}
|
||||
|
||||
export interface TemplateLiteralTypeSpan extends TypeNode {
|
||||
readonly kind: SyntaxKind.TemplateLiteralTypeSpan,
|
||||
readonly parent: TemplateLiteralTypeNode;
|
||||
readonly casing: TemplateCasing;
|
||||
readonly type: TypeNode;
|
||||
readonly literal: TemplateMiddle | TemplateTail;
|
||||
}
|
||||
|
||||
export const enum TemplateCasing {
|
||||
None,
|
||||
Uppercase,
|
||||
Lowercase,
|
||||
Capitalize,
|
||||
Uncapitalize,
|
||||
}
|
||||
|
||||
// Note: 'brands' in our syntax nodes serve to give us a small amount of nominal typing.
|
||||
// Consider 'Expression'. Without the brand, 'Expression' is actually no different
|
||||
// (structurally) than 'Node'. Because of this you can pass any Node to a function that
|
||||
@@ -2108,21 +2143,21 @@ namespace ts {
|
||||
|
||||
export interface TemplateHead extends TemplateLiteralLikeNode {
|
||||
readonly kind: SyntaxKind.TemplateHead;
|
||||
readonly parent: TemplateExpression;
|
||||
readonly parent: TemplateExpression | TemplateLiteralTypeNode;
|
||||
/* @internal */
|
||||
templateFlags?: TokenFlags;
|
||||
}
|
||||
|
||||
export interface TemplateMiddle extends TemplateLiteralLikeNode {
|
||||
readonly kind: SyntaxKind.TemplateMiddle;
|
||||
readonly parent: TemplateSpan;
|
||||
readonly parent: TemplateSpan | TemplateLiteralTypeSpan;
|
||||
/* @internal */
|
||||
templateFlags?: TokenFlags;
|
||||
}
|
||||
|
||||
export interface TemplateTail extends TemplateLiteralLikeNode {
|
||||
readonly kind: SyntaxKind.TemplateTail;
|
||||
readonly parent: TemplateSpan;
|
||||
readonly parent: TemplateSpan | TemplateLiteralTypeSpan;
|
||||
/* @internal */
|
||||
templateFlags?: TokenFlags;
|
||||
}
|
||||
@@ -4707,7 +4742,7 @@ namespace ts {
|
||||
/* @internal */
|
||||
export interface MappedSymbol extends TransientSymbol {
|
||||
mappedType: MappedType;
|
||||
mapper: TypeMapper;
|
||||
keyType: Type;
|
||||
}
|
||||
|
||||
/* @internal */
|
||||
@@ -4849,6 +4884,7 @@ namespace ts {
|
||||
Conditional = 1 << 24, // T extends U ? X : Y
|
||||
Substitution = 1 << 25, // Type parameter substitution
|
||||
NonPrimitive = 1 << 26, // intrinsic object type
|
||||
TemplateLiteral = 1 << 27, // Template literal type
|
||||
|
||||
/* @internal */
|
||||
AnyOrUnknown = Any | Unknown,
|
||||
@@ -4866,7 +4902,7 @@ namespace ts {
|
||||
Intrinsic = Any | Unknown | String | Number | BigInt | Boolean | BooleanLiteral | ESSymbol | Void | Undefined | Null | Never | NonPrimitive,
|
||||
/* @internal */
|
||||
Primitive = String | Number | BigInt | Boolean | Enum | EnumLiteral | ESSymbol | Void | Undefined | Null | Literal | UniqueESSymbol,
|
||||
StringLike = String | StringLiteral,
|
||||
StringLike = String | StringLiteral | TemplateLiteral,
|
||||
NumberLike = Number | NumberLiteral | Enum,
|
||||
BigIntLike = BigInt | BigIntLiteral,
|
||||
BooleanLike = Boolean | BooleanLiteral,
|
||||
@@ -4879,7 +4915,7 @@ namespace ts {
|
||||
StructuredType = Object | Union | Intersection,
|
||||
TypeVariable = TypeParameter | IndexedAccess,
|
||||
InstantiableNonPrimitive = TypeVariable | Conditional | Substitution,
|
||||
InstantiablePrimitive = Index,
|
||||
InstantiablePrimitive = Index | TemplateLiteral,
|
||||
Instantiable = InstantiableNonPrimitive | InstantiablePrimitive,
|
||||
StructuredOrInstantiable = StructuredType | Instantiable,
|
||||
/* @internal */
|
||||
@@ -4887,7 +4923,7 @@ namespace ts {
|
||||
/* @internal */
|
||||
Simplifiable = IndexedAccess | Conditional,
|
||||
/* @internal */
|
||||
Substructure = Object | Union | Intersection | Index | IndexedAccess | Conditional | Substitution,
|
||||
Substructure = Object | Union | Intersection | Index | IndexedAccess | Conditional | Substitution | TemplateLiteral,
|
||||
// 'Narrowable' types are types where narrowing actually narrows.
|
||||
// This *should* be every type other than null, undefined, void, and never
|
||||
Narrowable = Any | Unknown | StructuredOrInstantiable | StringLike | NumberLike | BigIntLike | BooleanLike | ESSymbol | UniqueESSymbol | NonPrimitive,
|
||||
@@ -5194,6 +5230,7 @@ namespace ts {
|
||||
declaration: MappedTypeNode;
|
||||
typeParameter?: TypeParameter;
|
||||
constraintType?: Type;
|
||||
nameType?: Type;
|
||||
templateType?: Type;
|
||||
modifiersType?: Type;
|
||||
resolvedApparentType?: Type;
|
||||
@@ -5334,6 +5371,12 @@ namespace ts {
|
||||
combinedMapper?: TypeMapper;
|
||||
}
|
||||
|
||||
export interface TemplateLiteralType extends InstantiableType {
|
||||
texts: readonly string[]; // Always one element longer than casings/types
|
||||
casings: readonly TemplateCasing[]; // Always at least one element
|
||||
types: readonly Type[]; // Always at least one element
|
||||
}
|
||||
|
||||
// Type parameter substitution (TypeFlags.Substitution)
|
||||
// Substitution types are created for type parameters or indexed access types that occur in the
|
||||
// true branch of a conditional type. For example, in 'T extends string ? Foo<T> : Bar<T>', the
|
||||
@@ -6715,6 +6758,8 @@ namespace ts {
|
||||
createIndexSignature(decorators: readonly Decorator[] | undefined, modifiers: readonly Modifier[] | undefined, parameters: readonly ParameterDeclaration[], type: TypeNode): IndexSignatureDeclaration;
|
||||
/* @internal */ createIndexSignature(decorators: readonly Decorator[] | undefined, modifiers: readonly Modifier[] | undefined, parameters: readonly ParameterDeclaration[], type: TypeNode | undefined): IndexSignatureDeclaration; // eslint-disable-line @typescript-eslint/unified-signatures
|
||||
updateIndexSignature(node: IndexSignatureDeclaration, decorators: readonly Decorator[] | undefined, modifiers: readonly Modifier[] | undefined, parameters: readonly ParameterDeclaration[], type: TypeNode): IndexSignatureDeclaration;
|
||||
createTemplateLiteralTypeSpan(casing: TemplateCasing, type: TypeNode, literal: TemplateMiddle | TemplateTail): TemplateLiteralTypeSpan;
|
||||
updateTemplateLiteralTypeSpan(casing: TemplateCasing, node: TemplateLiteralTypeSpan, type: TypeNode, literal: TemplateMiddle | TemplateTail): TemplateLiteralTypeSpan;
|
||||
|
||||
//
|
||||
// Types
|
||||
@@ -6760,10 +6805,12 @@ namespace ts {
|
||||
updateTypeOperatorNode(node: TypeOperatorNode, type: TypeNode): TypeOperatorNode;
|
||||
createIndexedAccessTypeNode(objectType: TypeNode, indexType: TypeNode): IndexedAccessTypeNode;
|
||||
updateIndexedAccessTypeNode(node: IndexedAccessTypeNode, objectType: TypeNode, indexType: TypeNode): IndexedAccessTypeNode;
|
||||
createMappedTypeNode(readonlyToken: ReadonlyKeyword | PlusToken | MinusToken | undefined, typeParameter: TypeParameterDeclaration, questionToken: QuestionToken | PlusToken | MinusToken | undefined, type: TypeNode | undefined): MappedTypeNode;
|
||||
updateMappedTypeNode(node: MappedTypeNode, readonlyToken: ReadonlyKeyword | PlusToken | MinusToken | undefined, typeParameter: TypeParameterDeclaration, questionToken: QuestionToken | PlusToken | MinusToken | undefined, type: TypeNode | undefined): MappedTypeNode;
|
||||
createMappedTypeNode(readonlyToken: ReadonlyKeyword | PlusToken | MinusToken | undefined, typeParameter: TypeParameterDeclaration, nameType: TypeNode | undefined, questionToken: QuestionToken | PlusToken | MinusToken | undefined, type: TypeNode | undefined): MappedTypeNode;
|
||||
updateMappedTypeNode(node: MappedTypeNode, readonlyToken: ReadonlyKeyword | PlusToken | MinusToken | undefined, typeParameter: TypeParameterDeclaration, nameType: TypeNode | undefined, questionToken: QuestionToken | PlusToken | MinusToken | undefined, type: TypeNode | undefined): MappedTypeNode;
|
||||
createLiteralTypeNode(literal: LiteralTypeNode["literal"]): LiteralTypeNode;
|
||||
updateLiteralTypeNode(node: LiteralTypeNode, literal: LiteralTypeNode["literal"]): LiteralTypeNode;
|
||||
createTemplateLiteralType(head: TemplateHead, templateSpans: readonly TemplateLiteralTypeSpan[]): TemplateLiteralTypeNode;
|
||||
updateTemplateLiteralType(node: TemplateLiteralTypeNode, head: TemplateHead, templateSpans: readonly TemplateLiteralTypeSpan[]): TemplateLiteralTypeNode;
|
||||
|
||||
//
|
||||
// Binding Patterns
|
||||
|
||||
@@ -565,6 +565,7 @@ namespace ts {
|
||||
return factory.updateMappedTypeNode((<MappedTypeNode>node),
|
||||
nodeVisitor((<MappedTypeNode>node).readonlyToken, tokenVisitor, isToken),
|
||||
nodeVisitor((<MappedTypeNode>node).typeParameter, visitor, isTypeParameterDeclaration),
|
||||
nodeVisitor((<MappedTypeNode>node).nameType, visitor, isTypeNode),
|
||||
nodeVisitor((<MappedTypeNode>node).questionToken, tokenVisitor, isToken),
|
||||
nodeVisitor((<MappedTypeNode>node).type, visitor, isTypeNode));
|
||||
|
||||
|
||||
@@ -48,6 +48,6 @@ namespace ts.codefix {
|
||||
|
||||
function doChange(changes: textChanges.ChangeTracker, sourceFile: SourceFile, { container, typeNode, constraint, name }: Info): void {
|
||||
changes.replaceNode(sourceFile, container, factory.createMappedTypeNode(/*readonlyToken*/ undefined,
|
||||
factory.createTypeParameterDeclaration(name, factory.createTypeReferenceNode(constraint)), /*questionToken*/ undefined, typeNode));
|
||||
factory.createTypeParameterDeclaration(name, factory.createTypeReferenceNode(constraint)), /*nameType*/ undefined, /*questionToken*/ undefined, typeNode));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -44,6 +44,7 @@ namespace ts.codefix {
|
||||
const mappedIntersectionType = factory.createMappedTypeNode(
|
||||
hasEffectiveReadonlyModifier(indexSignature) ? factory.createModifier(SyntaxKind.ReadonlyKeyword) : undefined,
|
||||
mappedTypeParameter,
|
||||
/*nameType*/ undefined,
|
||||
indexSignature.questionToken,
|
||||
indexSignature.type);
|
||||
const intersectionType = factory.createIntersectionTypeNode([
|
||||
|
||||
Reference in New Issue
Block a user