mirror of
https://github.com/microsoft/TypeScript.git
synced 2025-11-18 17:21:48 +00:00
Revert fix for intersections in template literals, fix differently (#52836)
This commit is contained in:
+17
-20
@@ -17070,32 +17070,24 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
|
||||
}
|
||||
return type;
|
||||
|
||||
function addSpans(texts: readonly string[] | string, types: readonly Type[]): boolean {
|
||||
const isTextsArray = isArray(texts);
|
||||
function addSpans(texts: readonly string[], types: readonly Type[]): boolean {
|
||||
for (let i = 0; i < types.length; i++) {
|
||||
const t = types[i];
|
||||
const addText = isTextsArray ? texts[i + 1] : texts;
|
||||
if (t.flags & (TypeFlags.Literal | TypeFlags.Null | TypeFlags.Undefined)) {
|
||||
text += getTemplateStringForType(t) || "";
|
||||
text += addText;
|
||||
if (!isTextsArray) return true;
|
||||
text += texts[i + 1];
|
||||
}
|
||||
else if (t.flags & TypeFlags.TemplateLiteral) {
|
||||
text += (t as TemplateLiteralType).texts[0];
|
||||
if (!addSpans((t as TemplateLiteralType).texts, (t as TemplateLiteralType).types)) return false;
|
||||
text += addText;
|
||||
if (!isTextsArray) return true;
|
||||
text += texts[i + 1];
|
||||
}
|
||||
else if (isGenericIndexType(t) || isPatternLiteralPlaceholderType(t)) {
|
||||
newTypes.push(t);
|
||||
newTexts.push(text);
|
||||
text = addText;
|
||||
text = texts[i + 1];
|
||||
}
|
||||
else if (t.flags & TypeFlags.Intersection) {
|
||||
const added = addSpans(texts[i + 1], (t as IntersectionType).types);
|
||||
if (!added) return false;
|
||||
}
|
||||
else if (isTextsArray) {
|
||||
else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -17113,6 +17105,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
|
||||
|
||||
function createTemplateLiteralType(texts: readonly string[], types: readonly Type[]) {
|
||||
const type = createType(TypeFlags.TemplateLiteral) as TemplateLiteralType;
|
||||
type.objectFlags = getPropagatingFlagsOfTypes(types, /*excludeKinds*/ TypeFlags.Nullable);
|
||||
type.texts = texts;
|
||||
type.types = types;
|
||||
return type;
|
||||
@@ -17120,6 +17113,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
|
||||
|
||||
function getStringMappingType(symbol: Symbol, type: Type): Type {
|
||||
return type.flags & (TypeFlags.Union | TypeFlags.Never) ? mapType(type, t => getStringMappingType(symbol, t)) :
|
||||
type.flags & TypeFlags.Intersection ? getIntersectionType(map((type as IntersectionType).types, t => getStringMappingType(symbol, t))) :
|
||||
type.flags & TypeFlags.StringLiteral ? getStringLiteralType(applyStringMapping(symbol, (type as StringLiteralType).value)) :
|
||||
type.flags & TypeFlags.TemplateLiteral ? getTemplateLiteralType(...applyTemplateStringMapping(symbol, (type as TemplateLiteralType).texts, (type as TemplateLiteralType).types)) :
|
||||
// Mapping<Mapping<T>> === Mapping<T>
|
||||
@@ -17423,6 +17417,9 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
|
||||
}
|
||||
|
||||
function isPatternLiteralPlaceholderType(type: Type): boolean {
|
||||
if (type.flags & TypeFlags.Intersection) {
|
||||
return some((type as IntersectionType).types, t => !!(t.flags & (TypeFlags.Literal | TypeFlags.Null | TypeFlags.Undefined)) || isPatternLiteralPlaceholderType(t));
|
||||
}
|
||||
return !!(type.flags & (TypeFlags.Any | TypeFlags.String | TypeFlags.Number | TypeFlags.BigInt)) || isPatternLiteralType(type);
|
||||
}
|
||||
|
||||
@@ -17444,12 +17441,12 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
|
||||
}
|
||||
|
||||
function getGenericObjectFlags(type: Type): ObjectFlags {
|
||||
if (type.flags & TypeFlags.UnionOrIntersection) {
|
||||
if (!((type as UnionOrIntersectionType).objectFlags & ObjectFlags.IsGenericTypeComputed)) {
|
||||
(type as UnionOrIntersectionType).objectFlags |= ObjectFlags.IsGenericTypeComputed |
|
||||
reduceLeft((type as UnionOrIntersectionType).types, (flags, t) => flags | getGenericObjectFlags(t), 0);
|
||||
if (type.flags & (TypeFlags.UnionOrIntersection | TypeFlags.TemplateLiteral)) {
|
||||
if (!((type as UnionOrIntersectionType | TemplateLiteralType).objectFlags & ObjectFlags.IsGenericTypeComputed)) {
|
||||
(type as UnionOrIntersectionType | TemplateLiteralType).objectFlags |= ObjectFlags.IsGenericTypeComputed |
|
||||
reduceLeft((type as UnionOrIntersectionType | TemplateLiteralType).types, (flags, t) => flags | getGenericObjectFlags(t), 0);
|
||||
}
|
||||
return (type as UnionOrIntersectionType).objectFlags & ObjectFlags.IsGenericType;
|
||||
return (type as UnionOrIntersectionType | TemplateLiteralType).objectFlags & ObjectFlags.IsGenericType;
|
||||
}
|
||||
if (type.flags & TypeFlags.Substitution) {
|
||||
if (!((type as SubstitutionType).objectFlags & ObjectFlags.IsGenericTypeComputed)) {
|
||||
@@ -17459,7 +17456,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
|
||||
return (type as SubstitutionType).objectFlags & ObjectFlags.IsGenericType;
|
||||
}
|
||||
return (type.flags & TypeFlags.InstantiableNonPrimitive || isGenericMappedType(type) || isGenericTupleType(type) ? ObjectFlags.IsGenericObjectType : 0) |
|
||||
(type.flags & (TypeFlags.InstantiableNonPrimitive | TypeFlags.Index | TypeFlags.TemplateLiteral | TypeFlags.StringMapping) && !isPatternLiteralType(type) ? ObjectFlags.IsGenericIndexType : 0);
|
||||
(type.flags & (TypeFlags.InstantiableNonPrimitive | TypeFlags.Index | TypeFlags.StringMapping) && !isPatternLiteralType(type) ? ObjectFlags.IsGenericIndexType : 0);
|
||||
}
|
||||
|
||||
function getSimplifiedType(type: Type, writing: boolean): Type {
|
||||
@@ -23896,7 +23893,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
|
||||
objectFlags & ObjectFlags.Reference && ((type as TypeReference).node || some(getTypeArguments(type as TypeReference), couldContainTypeVariables)) ||
|
||||
objectFlags & ObjectFlags.Anonymous && type.symbol && type.symbol.flags & (SymbolFlags.Function | SymbolFlags.Method | SymbolFlags.Class | SymbolFlags.TypeLiteral | SymbolFlags.ObjectLiteral) && type.symbol.declarations ||
|
||||
objectFlags & (ObjectFlags.Mapped | ObjectFlags.ReverseMapped | ObjectFlags.ObjectRestType | ObjectFlags.InstantiationExpressionType)) ||
|
||||
type.flags & TypeFlags.UnionOrIntersection && !(type.flags & TypeFlags.EnumLiteral) && !isNonGenericTopLevelType(type) && some((type as UnionOrIntersectionType).types, couldContainTypeVariables));
|
||||
type.flags & (TypeFlags.UnionOrIntersection | TypeFlags.TemplateLiteral) && !(type.flags & TypeFlags.EnumLiteral) && !isNonGenericTopLevelType(type) && some((type as UnionOrIntersectionType | TemplateLiteralType).types, couldContainTypeVariables));
|
||||
if (type.flags & TypeFlags.ObjectFlagsType) {
|
||||
(type as ObjectFlagsType).objectFlags |= ObjectFlags.CouldContainTypeVariablesComputed | (result ? ObjectFlags.CouldContainTypeVariables : 0);
|
||||
}
|
||||
|
||||
@@ -6107,7 +6107,7 @@ export const enum TypeFlags {
|
||||
Instantiable = InstantiableNonPrimitive | InstantiablePrimitive,
|
||||
StructuredOrInstantiable = StructuredType | Instantiable,
|
||||
/** @internal */
|
||||
ObjectFlagsType = Any | Nullable | Never | Object | Union | Intersection,
|
||||
ObjectFlagsType = Any | Nullable | Never | Object | Union | Intersection | TemplateLiteral,
|
||||
/** @internal */
|
||||
Simplifiable = IndexedAccess | Conditional,
|
||||
/** @internal */
|
||||
@@ -6261,7 +6261,7 @@ export const enum ObjectFlags {
|
||||
/** @internal */
|
||||
IdenticalBaseTypeExists = 1 << 26, // has a defined cachedEquivalentBaseType member
|
||||
|
||||
// Flags that require TypeFlags.UnionOrIntersection or TypeFlags.Substitution
|
||||
// Flags that require TypeFlags.UnionOrIntersection, TypeFlags.Substitution, or TypeFlags.TemplateLiteral
|
||||
/** @internal */
|
||||
IsGenericTypeComputed = 1 << 21, // IsGenericObjectType flag has been computed
|
||||
/** @internal */
|
||||
@@ -6288,7 +6288,7 @@ export const enum ObjectFlags {
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
export type ObjectFlagsType = NullableType | ObjectType | UnionType | IntersectionType;
|
||||
export type ObjectFlagsType = NullableType | ObjectType | UnionType | IntersectionType | TemplateLiteralType;
|
||||
|
||||
// Object types (TypeFlags.ObjectType)
|
||||
export interface ObjectType extends Type {
|
||||
@@ -6636,6 +6636,8 @@ export interface ConditionalType extends InstantiableType {
|
||||
}
|
||||
|
||||
export interface TemplateLiteralType extends InstantiableType {
|
||||
/** @internal */
|
||||
objectFlags: ObjectFlags;
|
||||
texts: readonly string[]; // Always one element longer than types
|
||||
types: readonly Type[]; // Always at least one element
|
||||
}
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
tests/cases/compiler/deeplyNestedTemplateLiteralIntersection.ts(20,11): error TS2590: Expression produces a union type that is too complex to represent.
|
||||
|
||||
|
||||
==== tests/cases/compiler/deeplyNestedTemplateLiteralIntersection.ts (1 errors) ====
|
||||
type R = `${number}a` & {
|
||||
_thing: true;
|
||||
};
|
||||
|
||||
type _S = "1" | "2" | "3" | "4" | "5" | "6";
|
||||
|
||||
type S = `${_S}${_S}${_S}`;
|
||||
|
||||
|
||||
type T = R | S;
|
||||
type X = `${T} ${T}`;
|
||||
|
||||
export type Props = Partial<{
|
||||
x: X;
|
||||
}>;
|
||||
|
||||
const a1: Props = {};
|
||||
const a2: Props = {};
|
||||
|
||||
const b = { ...a1, ...a2 };
|
||||
~~~~~~~~~~~~~~~~
|
||||
!!! error TS2590: Expression produces a union type that is too complex to represent.
|
||||
|
||||
export { b };
|
||||
|
||||
@@ -16,7 +16,7 @@ type OriginA1 = `${A}`
|
||||
>OriginA1 : "a"
|
||||
|
||||
type OriginA2 = `${MixA}`
|
||||
>OriginA2 : "a"
|
||||
>OriginA2 : `${MixA}`
|
||||
|
||||
type B = `${typeof a}`
|
||||
>B : "a"
|
||||
@@ -30,14 +30,14 @@ type OriginB1 = `${B}`
|
||||
>OriginB1 : "a"
|
||||
|
||||
type OriginB2 = `${MixB}`
|
||||
>OriginB2 : "a"
|
||||
>OriginB2 : `${MixB}`
|
||||
|
||||
type MixC = { foo: string } & A
|
||||
>MixC : { foo: string; } & "a"
|
||||
>foo : string
|
||||
|
||||
type OriginC = `${MixC}`
|
||||
>OriginC : "a"
|
||||
>OriginC : `${MixC}`
|
||||
|
||||
type MixD<T extends string> =
|
||||
>MixD : `${T & { foo: string; }}`
|
||||
@@ -46,7 +46,7 @@ type MixD<T extends string> =
|
||||
>foo : string
|
||||
|
||||
type OriginD = `${MixD<A & { foo: string }> & { foo: string }}`;
|
||||
>OriginD : "a"
|
||||
>OriginD : `${`${"a" & { foo: string; } & { foo: string; }}` & { foo: string; }}`
|
||||
>foo : string
|
||||
>foo : string
|
||||
|
||||
|
||||
@@ -0,0 +1,41 @@
|
||||
tests/cases/compiler/templateLiteralIntersection2.ts(7,12): error TS2345: Argument of type '"foo/bar"' is not assignable to parameter of type '`${Path}/${Path}`'.
|
||||
tests/cases/compiler/templateLiteralIntersection2.ts(20,10): error TS2345: Argument of type '""' is not assignable to parameter of type '`a${string}` & `${string}a`'.
|
||||
Type '""' is not assignable to type '`a${string}`'.
|
||||
tests/cases/compiler/templateLiteralIntersection2.ts(22,10): error TS2345: Argument of type '"ab"' is not assignable to parameter of type '`a${string}` & `${string}a`'.
|
||||
Type '"ab"' is not assignable to type '`${string}a`'.
|
||||
|
||||
|
||||
==== tests/cases/compiler/templateLiteralIntersection2.ts (3 errors) ====
|
||||
type Path = string & { _pathBrand: any };
|
||||
|
||||
type JoinedPath = `${Path}/${Path}`;
|
||||
|
||||
declare function joinedPath(p: JoinedPath): void;
|
||||
|
||||
joinedPath("foo/bar");
|
||||
~~~~~~~~~
|
||||
!!! error TS2345: Argument of type '"foo/bar"' is not assignable to parameter of type '`${Path}/${Path}`'.
|
||||
|
||||
declare const somePath: Path;
|
||||
|
||||
joinedPath(`${somePath}/${somePath}`);
|
||||
|
||||
|
||||
type StartsWithA = `a${string}`;
|
||||
type EndsWithA = `${string}a`;
|
||||
|
||||
|
||||
declare function withinAs(p: StartsWithA & EndsWithA): void;
|
||||
|
||||
withinAs("");
|
||||
~~
|
||||
!!! error TS2345: Argument of type '""' is not assignable to parameter of type '`a${string}` & `${string}a`'.
|
||||
!!! error TS2345: Type '""' is not assignable to type '`a${string}`'.
|
||||
withinAs("a");
|
||||
withinAs("ab");
|
||||
~~~~
|
||||
!!! error TS2345: Argument of type '"ab"' is not assignable to parameter of type '`a${string}` & `${string}a`'.
|
||||
!!! error TS2345: Type '"ab"' is not assignable to type '`${string}a`'.
|
||||
withinAs("aba");
|
||||
withinAs("abavvvva");
|
||||
|
||||
@@ -0,0 +1,56 @@
|
||||
=== tests/cases/compiler/templateLiteralIntersection2.ts ===
|
||||
type Path = string & { _pathBrand: any };
|
||||
>Path : Symbol(Path, Decl(templateLiteralIntersection2.ts, 0, 0))
|
||||
>_pathBrand : Symbol(_pathBrand, Decl(templateLiteralIntersection2.ts, 0, 22))
|
||||
|
||||
type JoinedPath = `${Path}/${Path}`;
|
||||
>JoinedPath : Symbol(JoinedPath, Decl(templateLiteralIntersection2.ts, 0, 41))
|
||||
>Path : Symbol(Path, Decl(templateLiteralIntersection2.ts, 0, 0))
|
||||
>Path : Symbol(Path, Decl(templateLiteralIntersection2.ts, 0, 0))
|
||||
|
||||
declare function joinedPath(p: JoinedPath): void;
|
||||
>joinedPath : Symbol(joinedPath, Decl(templateLiteralIntersection2.ts, 2, 36))
|
||||
>p : Symbol(p, Decl(templateLiteralIntersection2.ts, 4, 28))
|
||||
>JoinedPath : Symbol(JoinedPath, Decl(templateLiteralIntersection2.ts, 0, 41))
|
||||
|
||||
joinedPath("foo/bar");
|
||||
>joinedPath : Symbol(joinedPath, Decl(templateLiteralIntersection2.ts, 2, 36))
|
||||
|
||||
declare const somePath: Path;
|
||||
>somePath : Symbol(somePath, Decl(templateLiteralIntersection2.ts, 8, 13))
|
||||
>Path : Symbol(Path, Decl(templateLiteralIntersection2.ts, 0, 0))
|
||||
|
||||
joinedPath(`${somePath}/${somePath}`);
|
||||
>joinedPath : Symbol(joinedPath, Decl(templateLiteralIntersection2.ts, 2, 36))
|
||||
>somePath : Symbol(somePath, Decl(templateLiteralIntersection2.ts, 8, 13))
|
||||
>somePath : Symbol(somePath, Decl(templateLiteralIntersection2.ts, 8, 13))
|
||||
|
||||
|
||||
type StartsWithA = `a${string}`;
|
||||
>StartsWithA : Symbol(StartsWithA, Decl(templateLiteralIntersection2.ts, 10, 38))
|
||||
|
||||
type EndsWithA = `${string}a`;
|
||||
>EndsWithA : Symbol(EndsWithA, Decl(templateLiteralIntersection2.ts, 13, 32))
|
||||
|
||||
|
||||
declare function withinAs(p: StartsWithA & EndsWithA): void;
|
||||
>withinAs : Symbol(withinAs, Decl(templateLiteralIntersection2.ts, 14, 30))
|
||||
>p : Symbol(p, Decl(templateLiteralIntersection2.ts, 17, 26))
|
||||
>StartsWithA : Symbol(StartsWithA, Decl(templateLiteralIntersection2.ts, 10, 38))
|
||||
>EndsWithA : Symbol(EndsWithA, Decl(templateLiteralIntersection2.ts, 13, 32))
|
||||
|
||||
withinAs("");
|
||||
>withinAs : Symbol(withinAs, Decl(templateLiteralIntersection2.ts, 14, 30))
|
||||
|
||||
withinAs("a");
|
||||
>withinAs : Symbol(withinAs, Decl(templateLiteralIntersection2.ts, 14, 30))
|
||||
|
||||
withinAs("ab");
|
||||
>withinAs : Symbol(withinAs, Decl(templateLiteralIntersection2.ts, 14, 30))
|
||||
|
||||
withinAs("aba");
|
||||
>withinAs : Symbol(withinAs, Decl(templateLiteralIntersection2.ts, 14, 30))
|
||||
|
||||
withinAs("abavvvva");
|
||||
>withinAs : Symbol(withinAs, Decl(templateLiteralIntersection2.ts, 14, 30))
|
||||
|
||||
@@ -0,0 +1,64 @@
|
||||
=== tests/cases/compiler/templateLiteralIntersection2.ts ===
|
||||
type Path = string & { _pathBrand: any };
|
||||
>Path : string & { _pathBrand: any; }
|
||||
>_pathBrand : any
|
||||
|
||||
type JoinedPath = `${Path}/${Path}`;
|
||||
>JoinedPath : `${Path}/${Path}`
|
||||
|
||||
declare function joinedPath(p: JoinedPath): void;
|
||||
>joinedPath : (p: JoinedPath) => void
|
||||
>p : `${Path}/${Path}`
|
||||
|
||||
joinedPath("foo/bar");
|
||||
>joinedPath("foo/bar") : void
|
||||
>joinedPath : (p: `${Path}/${Path}`) => void
|
||||
>"foo/bar" : "foo/bar"
|
||||
|
||||
declare const somePath: Path;
|
||||
>somePath : Path
|
||||
|
||||
joinedPath(`${somePath}/${somePath}`);
|
||||
>joinedPath(`${somePath}/${somePath}`) : void
|
||||
>joinedPath : (p: `${Path}/${Path}`) => void
|
||||
>`${somePath}/${somePath}` : `${Path}/${Path}`
|
||||
>somePath : Path
|
||||
>somePath : Path
|
||||
|
||||
|
||||
type StartsWithA = `a${string}`;
|
||||
>StartsWithA : `a${string}`
|
||||
|
||||
type EndsWithA = `${string}a`;
|
||||
>EndsWithA : `${string}a`
|
||||
|
||||
|
||||
declare function withinAs(p: StartsWithA & EndsWithA): void;
|
||||
>withinAs : (p: StartsWithA & EndsWithA) => void
|
||||
>p : `a${string}` & `${string}a`
|
||||
|
||||
withinAs("");
|
||||
>withinAs("") : void
|
||||
>withinAs : (p: `a${string}` & `${string}a`) => void
|
||||
>"" : ""
|
||||
|
||||
withinAs("a");
|
||||
>withinAs("a") : void
|
||||
>withinAs : (p: `a${string}` & `${string}a`) => void
|
||||
>"a" : "a"
|
||||
|
||||
withinAs("ab");
|
||||
>withinAs("ab") : void
|
||||
>withinAs : (p: `a${string}` & `${string}a`) => void
|
||||
>"ab" : "ab"
|
||||
|
||||
withinAs("aba");
|
||||
>withinAs("aba") : void
|
||||
>withinAs : (p: `a${string}` & `${string}a`) => void
|
||||
>"aba" : "aba"
|
||||
|
||||
withinAs("abavvvva");
|
||||
>withinAs("abavvvva") : void
|
||||
>withinAs : (p: `a${string}` & `${string}a`) => void
|
||||
>"abavvvva" : "abavvvva"
|
||||
|
||||
@@ -0,0 +1,32 @@
|
||||
=== tests/cases/compiler/templateLiteralIntersection3.ts ===
|
||||
type Path = string & { _pathBrand: any };
|
||||
>Path : Symbol(Path, Decl(templateLiteralIntersection3.ts, 0, 0))
|
||||
>_pathBrand : Symbol(_pathBrand, Decl(templateLiteralIntersection3.ts, 0, 22))
|
||||
|
||||
declare const path: Path;
|
||||
>path : Symbol(path, Decl(templateLiteralIntersection3.ts, 1, 13))
|
||||
>Path : Symbol(Path, Decl(templateLiteralIntersection3.ts, 0, 0))
|
||||
|
||||
declare const options1: { prop: number; } & { [k: string]: boolean; };
|
||||
>options1 : Symbol(options1, Decl(templateLiteralIntersection3.ts, 3, 13))
|
||||
>prop : Symbol(prop, Decl(templateLiteralIntersection3.ts, 3, 25))
|
||||
>k : Symbol(k, Decl(templateLiteralIntersection3.ts, 3, 47))
|
||||
|
||||
options1[`foo`] = false;
|
||||
>options1 : Symbol(options1, Decl(templateLiteralIntersection3.ts, 3, 13))
|
||||
|
||||
options1[`foo/${path}`] = false;
|
||||
>options1 : Symbol(options1, Decl(templateLiteralIntersection3.ts, 3, 13))
|
||||
>path : Symbol(path, Decl(templateLiteralIntersection3.ts, 1, 13))
|
||||
|
||||
|
||||
// Lowercase<`foo/${Path}`> => `foo/${Lowercase<Path>}`
|
||||
declare const lowercasePath: Lowercase<`foo/${Path}`>;
|
||||
>lowercasePath : Symbol(lowercasePath, Decl(templateLiteralIntersection3.ts, 11, 13))
|
||||
>Lowercase : Symbol(Lowercase, Decl(lib.es5.d.ts, --, --))
|
||||
>Path : Symbol(Path, Decl(templateLiteralIntersection3.ts, 0, 0))
|
||||
|
||||
options1[lowercasePath] = false;
|
||||
>options1 : Symbol(options1, Decl(templateLiteralIntersection3.ts, 3, 13))
|
||||
>lowercasePath : Symbol(lowercasePath, Decl(templateLiteralIntersection3.ts, 11, 13))
|
||||
|
||||
@@ -0,0 +1,40 @@
|
||||
=== tests/cases/compiler/templateLiteralIntersection3.ts ===
|
||||
type Path = string & { _pathBrand: any };
|
||||
>Path : string & { _pathBrand: any; }
|
||||
>_pathBrand : any
|
||||
|
||||
declare const path: Path;
|
||||
>path : Path
|
||||
|
||||
declare const options1: { prop: number; } & { [k: string]: boolean; };
|
||||
>options1 : { prop: number; } & { [k: string]: boolean; }
|
||||
>prop : number
|
||||
>k : string
|
||||
|
||||
options1[`foo`] = false;
|
||||
>options1[`foo`] = false : false
|
||||
>options1[`foo`] : boolean
|
||||
>options1 : { prop: number; } & { [k: string]: boolean; }
|
||||
>`foo` : "foo"
|
||||
>false : false
|
||||
|
||||
options1[`foo/${path}`] = false;
|
||||
>options1[`foo/${path}`] = false : false
|
||||
>options1[`foo/${path}`] : boolean
|
||||
>options1 : { prop: number; } & { [k: string]: boolean; }
|
||||
>`foo/${path}` : `foo/${Path}`
|
||||
>path : Path
|
||||
>false : false
|
||||
|
||||
|
||||
// Lowercase<`foo/${Path}`> => `foo/${Lowercase<Path>}`
|
||||
declare const lowercasePath: Lowercase<`foo/${Path}`>;
|
||||
>lowercasePath : `foo/${Lowercase<string> & { _pathBrand: any; }}`
|
||||
|
||||
options1[lowercasePath] = false;
|
||||
>options1[lowercasePath] = false : false
|
||||
>options1[lowercasePath] : boolean
|
||||
>options1 : { prop: number; } & { [k: string]: boolean; }
|
||||
>lowercasePath : `foo/${Lowercase<string> & { _pathBrand: any; }}`
|
||||
>false : false
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
// @strict: true
|
||||
// @noEmit: true
|
||||
// @noTypesAndSymbols: true
|
||||
|
||||
|
||||
type R = `${number}a` & {
|
||||
_thing: true;
|
||||
};
|
||||
|
||||
type _S = "1" | "2" | "3" | "4" | "5" | "6";
|
||||
|
||||
type S = `${_S}${_S}${_S}`;
|
||||
|
||||
|
||||
type T = R | S;
|
||||
type X = `${T} ${T}`;
|
||||
|
||||
export type Props = Partial<{
|
||||
x: X;
|
||||
}>;
|
||||
|
||||
const a1: Props = {};
|
||||
const a2: Props = {};
|
||||
|
||||
const b = { ...a1, ...a2 };
|
||||
|
||||
export { b };
|
||||
@@ -0,0 +1,27 @@
|
||||
// @strict: true
|
||||
// @noEmit: true
|
||||
|
||||
type Path = string & { _pathBrand: any };
|
||||
|
||||
type JoinedPath = `${Path}/${Path}`;
|
||||
|
||||
declare function joinedPath(p: JoinedPath): void;
|
||||
|
||||
joinedPath("foo/bar");
|
||||
|
||||
declare const somePath: Path;
|
||||
|
||||
joinedPath(`${somePath}/${somePath}`);
|
||||
|
||||
|
||||
type StartsWithA = `a${string}`;
|
||||
type EndsWithA = `${string}a`;
|
||||
|
||||
|
||||
declare function withinAs(p: StartsWithA & EndsWithA): void;
|
||||
|
||||
withinAs("");
|
||||
withinAs("a");
|
||||
withinAs("ab");
|
||||
withinAs("aba");
|
||||
withinAs("abavvvva");
|
||||
@@ -0,0 +1,17 @@
|
||||
// @strict: true
|
||||
// @noEmit: true
|
||||
|
||||
type Path = string & { _pathBrand: any };
|
||||
declare const path: Path;
|
||||
|
||||
declare const options1: { prop: number; } & { [k: string]: boolean; };
|
||||
|
||||
options1[`foo`] = false;
|
||||
|
||||
options1[`foo/${path}`] = false;
|
||||
|
||||
|
||||
// Lowercase<`foo/${Path}`> => `foo/${Lowercase<Path>}`
|
||||
declare const lowercasePath: Lowercase<`foo/${Path}`>;
|
||||
|
||||
options1[lowercasePath] = false;
|
||||
Reference in New Issue
Block a user