Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions tsc/internal/checker/checker.go
Original file line number Diff line number Diff line change
Expand Up @@ -636,7 +636,7 @@ type Checker struct {
subtypeReductionCache map[CacheHashKey][]*Type
cachedTypes map[CachedTypeKey]*Type
cachedSignatures map[CachedSignatureKey]*Signature
undefinedProperties map[string]*ast.Symbol
undefinedProperties map[*ast.Symbol]*ast.Symbol
narrowedTypes map[NarrowedTypeKey]*Type
assignmentReducedTypes map[AssignmentReducedKey]*Type
discriminatedContextualTypes map[DiscriminatedContextualTypeKey]*Type
Expand Down Expand Up @@ -955,7 +955,7 @@ func NewChecker(program Program, tracer *Tracer) (*Checker, *sync.Mutex) {
c.subtypeReductionCache = make(map[CacheHashKey][]*Type)
c.cachedTypes = make(map[CachedTypeKey]*Type)
c.cachedSignatures = make(map[CachedSignatureKey]*Signature)
c.undefinedProperties = make(map[string]*ast.Symbol)
c.undefinedProperties = make(map[*ast.Symbol]*ast.Symbol)
c.narrowedTypes = make(map[NarrowedTypeKey]*Type)
c.assignmentReducedTypes = make(map[AssignmentReducedKey]*Type)
c.discriminatedContextualTypes = make(map[DiscriminatedContextualTypeKey]*Type)
Expand Down Expand Up @@ -18907,12 +18907,12 @@ func (c *Checker) getSiblingsOfContext(context *WideningContext) []*Type {
}

func (c *Checker) getUndefinedProperty(prop *ast.Symbol) *ast.Symbol {
if cached := c.undefinedProperties[prop.Name()]; cached != nil {
if cached := c.undefinedProperties[prop]; cached != nil {
return cached
}
result := c.createSymbolWithType(prop, c.undefinedOrMissingType)
result.SetFlags(result.Flags() | ast.SymbolFlagsOptional)
c.undefinedProperties[prop.Name()] = result
c.undefinedProperties[prop] = result
return result
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
//// [tests/cases/compiler/undefinedPropertyDeclarationOrder.ts] ////

//// [undefinedPropertyDeclarationOrder.ts]
export const a = Math.random() > 0.5 ? { user: 1 } : { status: "a" };
export const b = Math.random() > 0.5 ? { status: "no" } : { status: "ok", user: 2 };




//// [undefinedPropertyDeclarationOrder.d.ts]
export declare const a: {
user: number;
status?: undefined;
} | {
user?: undefined;
status: string;
};
export declare const b: {
status: string;
user?: undefined;
} | {
status: string;
user: number;
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
//// [tests/cases/compiler/undefinedPropertyDeclarationOrder.ts] ////

=== undefinedPropertyDeclarationOrder.ts ===
export const a = Math.random() > 0.5 ? { user: 1 } : { status: "a" };
>a : Symbol(a, Decl(undefinedPropertyDeclarationOrder.ts, 0, 12))
>Math.random : Symbol(Math.random, Decl(lib.es5.d.ts, --, --))
>Math : Symbol(Math, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --), Decl(lib.es2015.core.d.ts, --, --), Decl(lib.es2015.symbol.wellknown.d.ts, --, --), Decl(lib.es2025.float16.d.ts, --, --) ... and 1 more)
>random : Symbol(Math.random, Decl(lib.es5.d.ts, --, --))
>user : Symbol(user, Decl(undefinedPropertyDeclarationOrder.ts, 0, 40))
>status : Symbol(status, Decl(undefinedPropertyDeclarationOrder.ts, 0, 54))

export const b = Math.random() > 0.5 ? { status: "no" } : { status: "ok", user: 2 };
>b : Symbol(b, Decl(undefinedPropertyDeclarationOrder.ts, 1, 12))
>Math.random : Symbol(Math.random, Decl(lib.es5.d.ts, --, --))
>Math : Symbol(Math, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --), Decl(lib.es2015.core.d.ts, --, --), Decl(lib.es2015.symbol.wellknown.d.ts, --, --), Decl(lib.es2025.float16.d.ts, --, --) ... and 1 more)
>random : Symbol(Math.random, Decl(lib.es5.d.ts, --, --))
>status : Symbol(status, Decl(undefinedPropertyDeclarationOrder.ts, 1, 40))
>status : Symbol(status, Decl(undefinedPropertyDeclarationOrder.ts, 1, 59))
>user : Symbol(user, Decl(undefinedPropertyDeclarationOrder.ts, 1, 73))

Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
//// [tests/cases/compiler/undefinedPropertyDeclarationOrder.ts] ////

=== undefinedPropertyDeclarationOrder.ts ===
export const a = Math.random() > 0.5 ? { user: 1 } : { status: "a" };
>a : { user: number; status?: undefined; } | { user?: undefined; status: string; }
>Math.random() > 0.5 ? { user: 1 } : { status: "a" } : { user: number; } | { status: string; }
>Math.random() > 0.5 : boolean
>Math.random() : number
>Math.random : () => number
>Math : Math
>random : () => number
>0.5 : 0.5
>{ user: 1 } : { user: number; }
>user : number
>1 : 1
>{ status: "a" } : { status: string; }
>status : string
>"a" : "a"

export const b = Math.random() > 0.5 ? { status: "no" } : { status: "ok", user: 2 };
>b : { status: string; user?: undefined; } | { status: string; user: number; }
>Math.random() > 0.5 ? { status: "no" } : { status: "ok", user: 2 } : { status: string; } | { status: string; user: number; }
>Math.random() > 0.5 : boolean
>Math.random() : number
>Math.random : () => number
>Math : Math
>random : () => number
>0.5 : 0.5
>{ status: "no" } : { status: string; }
>status : string
>"no" : "no"
>{ status: "ok", user: 2 } : { status: string; user: number; }
>status : string
>"ok" : "ok"
>user : number
>2 : 2

Original file line number Diff line number Diff line change
Expand Up @@ -160,35 +160,35 @@ declare let c3: {
a: number;
b: number;
} | {
b?: undefined;
a?: undefined;
b?: undefined;
};
declare let c4: {
b?: undefined;
a?: undefined;
b?: undefined;
} | {
a: number;
b: number;
};
declare let d1: {
kind: string;
pos: {
b?: undefined;
a?: undefined;
x: number;
y: number;
a?: undefined;
b?: undefined;
};
} | {
kind: string;
pos: {
b?: undefined;
x?: undefined;
y?: undefined;
a: string;
b?: undefined;
} | {
a?: undefined;
x?: undefined;
y?: undefined;
a?: undefined;
b: number;
};
};
Expand All @@ -209,11 +209,11 @@ declare let e1: {
a?: undefined;
};
declare let e2: {
b?: undefined;
a?: undefined;
} | {
b?: undefined;
} | {
a: string;
b?: undefined;
} | {
a: number;
b: number;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,9 +55,9 @@ a2.a; // string | number | undefined
>a : Symbol(a, Decl(objectLiteralNormalization.ts, 10, 11), Decl(objectLiteralNormalization.ts, 10, 27))

a2.b; // number | undefined
>a2.b : Symbol(b, Decl(objectLiteralNormalization.ts, 10, 17), Decl(objectLiteralNormalization.ts, 1, 45))
>a2.b : Symbol(b, Decl(objectLiteralNormalization.ts, 10, 17))
>a2 : Symbol(a2, Decl(objectLiteralNormalization.ts, 10, 3))
>b : Symbol(b, Decl(objectLiteralNormalization.ts, 10, 17), Decl(objectLiteralNormalization.ts, 1, 45))
>b : Symbol(b, Decl(objectLiteralNormalization.ts, 10, 17))

a2 = { a: 10, b: 20 };
>a2 : Symbol(a2, Decl(objectLiteralNormalization.ts, 10, 3))
Expand Down Expand Up @@ -160,18 +160,18 @@ d1.pos.y;
>y : Symbol(y, Decl(objectLiteralNormalization.ts, 33, 35))

d1.pos.a;
>d1.pos.a : Symbol(a, Decl(objectLiteralNormalization.ts, 10, 27), Decl(objectLiteralNormalization.ts, 33, 73))
>d1.pos.a : Symbol(a, Decl(objectLiteralNormalization.ts, 33, 73))
>d1.pos : Symbol(pos, Decl(objectLiteralNormalization.ts, 33, 22), Decl(objectLiteralNormalization.ts, 33, 58))
>d1 : Symbol(d1, Decl(objectLiteralNormalization.ts, 33, 3))
>pos : Symbol(pos, Decl(objectLiteralNormalization.ts, 33, 22), Decl(objectLiteralNormalization.ts, 33, 58))
>a : Symbol(a, Decl(objectLiteralNormalization.ts, 10, 27), Decl(objectLiteralNormalization.ts, 33, 73))
>a : Symbol(a, Decl(objectLiteralNormalization.ts, 33, 73))

d1.pos.b;
>d1.pos.b : Symbol(b, Decl(objectLiteralNormalization.ts, 1, 45), Decl(objectLiteralNormalization.ts, 33, 86))
>d1.pos.b : Symbol(b, Decl(objectLiteralNormalization.ts, 33, 86))
>d1.pos : Symbol(pos, Decl(objectLiteralNormalization.ts, 33, 22), Decl(objectLiteralNormalization.ts, 33, 58))
>d1 : Symbol(d1, Decl(objectLiteralNormalization.ts, 33, 3))
>pos : Symbol(pos, Decl(objectLiteralNormalization.ts, 33, 22), Decl(objectLiteralNormalization.ts, 33, 58))
>b : Symbol(b, Decl(objectLiteralNormalization.ts, 1, 45), Decl(objectLiteralNormalization.ts, 33, 86))
>b : Symbol(b, Decl(objectLiteralNormalization.ts, 33, 86))

declare function f<T>(...items: T[]): T;
>f : Symbol(f, Decl(objectLiteralNormalization.ts, 39, 9))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -175,7 +175,7 @@ let c2 = !true ? opts : {};
>{} : {}

let c3 = !true ? { a: 0, b: 0 } : {};
>c3 : { a: number; b: number; } | { b?: undefined; a?: undefined; }
>c3 : { a: number; b: number; } | { a?: undefined; b?: undefined; }
>!true ? { a: 0, b: 0 } : {} : { a: number; b: number; } | {}
>!true : false
>true : true
Expand All @@ -187,7 +187,7 @@ let c3 = !true ? { a: 0, b: 0 } : {};
>{} : {}

let c4 = !true ? {} : { a: 0, b: 0 };
>c4 : { b?: undefined; a?: undefined; } | { a: number; b: number; }
>c4 : { a?: undefined; b?: undefined; } | { a: number; b: number; }
>!true ? {} : { a: 0, b: 0 } : {} | { a: number; b: number; }
>!true : false
>true : true
Expand All @@ -200,7 +200,7 @@ let c4 = !true ? {} : { a: 0, b: 0 };

// Normalization applies to nested properties
let d1 = [{ kind: 'a', pos: { x: 0, y: 0 } }, { kind: 'b', pos: !true ? { a: "x" } : { b: 0 } }][0];
>d1 : { kind: string; pos: { b?: undefined; a?: undefined; x: number; y: number; }; } | { kind: string; pos: { b?: undefined; x?: undefined; y?: undefined; a: string; } | { a?: undefined; x?: undefined; y?: undefined; b: number; }; }
>d1 : { kind: string; pos: { x: number; y: number; a?: undefined; b?: undefined; }; } | { kind: string; pos: { x?: undefined; y?: undefined; a: string; b?: undefined; } | { x?: undefined; y?: undefined; a?: undefined; b: number; }; }
>[{ kind: 'a', pos: { x: 0, y: 0 } }, { kind: 'b', pos: !true ? { a: "x" } : { b: 0 } }][0] : { kind: string; pos: { x: number; y: number; }; } | { kind: string; pos: { a: string; } | { b: number; }; }
>[{ kind: 'a', pos: { x: 0, y: 0 } }, { kind: 'b', pos: !true ? { a: "x" } : { b: 0 } }] : ({ kind: string; pos: { x: number; y: number; }; } | { kind: string; pos: { a: string; } | { b: number; }; })[]
>{ kind: 'a', pos: { x: 0, y: 0 } } : { kind: string; pos: { x: number; y: number; }; }
Expand Down Expand Up @@ -229,40 +229,40 @@ let d1 = [{ kind: 'a', pos: { x: 0, y: 0 } }, { kind: 'b', pos: !true ? { a: "x"

d1.kind;
>d1.kind : string
>d1 : { kind: string; pos: { b?: undefined; a?: undefined; x: number; y: number; }; } | { kind: string; pos: { b?: undefined; x?: undefined; y?: undefined; a: string; } | { a?: undefined; x?: undefined; y?: undefined; b: number; }; }
>d1 : { kind: string; pos: { x: number; y: number; a?: undefined; b?: undefined; }; } | { kind: string; pos: { x?: undefined; y?: undefined; a: string; b?: undefined; } | { x?: undefined; y?: undefined; a?: undefined; b: number; }; }
>kind : string

d1.pos;
>d1.pos : { b?: undefined; a?: undefined; x: number; y: number; } | { b?: undefined; x?: undefined; y?: undefined; a: string; } | { a?: undefined; x?: undefined; y?: undefined; b: number; }
>d1 : { kind: string; pos: { b?: undefined; a?: undefined; x: number; y: number; }; } | { kind: string; pos: { b?: undefined; x?: undefined; y?: undefined; a: string; } | { a?: undefined; x?: undefined; y?: undefined; b: number; }; }
>pos : { b?: undefined; a?: undefined; x: number; y: number; } | { b?: undefined; x?: undefined; y?: undefined; a: string; } | { a?: undefined; x?: undefined; y?: undefined; b: number; }
>d1.pos : { x: number; y: number; a?: undefined; b?: undefined; } | { x?: undefined; y?: undefined; a: string; b?: undefined; } | { x?: undefined; y?: undefined; a?: undefined; b: number; }
>d1 : { kind: string; pos: { x: number; y: number; a?: undefined; b?: undefined; }; } | { kind: string; pos: { x?: undefined; y?: undefined; a: string; b?: undefined; } | { x?: undefined; y?: undefined; a?: undefined; b: number; }; }
>pos : { x: number; y: number; a?: undefined; b?: undefined; } | { x?: undefined; y?: undefined; a: string; b?: undefined; } | { x?: undefined; y?: undefined; a?: undefined; b: number; }

d1.pos.x;
>d1.pos.x : number | undefined
>d1.pos : { b?: undefined; a?: undefined; x: number; y: number; } | { b?: undefined; x?: undefined; y?: undefined; a: string; } | { a?: undefined; x?: undefined; y?: undefined; b: number; }
>d1 : { kind: string; pos: { b?: undefined; a?: undefined; x: number; y: number; }; } | { kind: string; pos: { b?: undefined; x?: undefined; y?: undefined; a: string; } | { a?: undefined; x?: undefined; y?: undefined; b: number; }; }
>pos : { b?: undefined; a?: undefined; x: number; y: number; } | { b?: undefined; x?: undefined; y?: undefined; a: string; } | { a?: undefined; x?: undefined; y?: undefined; b: number; }
>d1.pos : { x: number; y: number; a?: undefined; b?: undefined; } | { x?: undefined; y?: undefined; a: string; b?: undefined; } | { x?: undefined; y?: undefined; a?: undefined; b: number; }
>d1 : { kind: string; pos: { x: number; y: number; a?: undefined; b?: undefined; }; } | { kind: string; pos: { x?: undefined; y?: undefined; a: string; b?: undefined; } | { x?: undefined; y?: undefined; a?: undefined; b: number; }; }
>pos : { x: number; y: number; a?: undefined; b?: undefined; } | { x?: undefined; y?: undefined; a: string; b?: undefined; } | { x?: undefined; y?: undefined; a?: undefined; b: number; }
>x : number | undefined

d1.pos.y;
>d1.pos.y : number | undefined
>d1.pos : { b?: undefined; a?: undefined; x: number; y: number; } | { b?: undefined; x?: undefined; y?: undefined; a: string; } | { a?: undefined; x?: undefined; y?: undefined; b: number; }
>d1 : { kind: string; pos: { b?: undefined; a?: undefined; x: number; y: number; }; } | { kind: string; pos: { b?: undefined; x?: undefined; y?: undefined; a: string; } | { a?: undefined; x?: undefined; y?: undefined; b: number; }; }
>pos : { b?: undefined; a?: undefined; x: number; y: number; } | { b?: undefined; x?: undefined; y?: undefined; a: string; } | { a?: undefined; x?: undefined; y?: undefined; b: number; }
>d1.pos : { x: number; y: number; a?: undefined; b?: undefined; } | { x?: undefined; y?: undefined; a: string; b?: undefined; } | { x?: undefined; y?: undefined; a?: undefined; b: number; }
>d1 : { kind: string; pos: { x: number; y: number; a?: undefined; b?: undefined; }; } | { kind: string; pos: { x?: undefined; y?: undefined; a: string; b?: undefined; } | { x?: undefined; y?: undefined; a?: undefined; b: number; }; }
>pos : { x: number; y: number; a?: undefined; b?: undefined; } | { x?: undefined; y?: undefined; a: string; b?: undefined; } | { x?: undefined; y?: undefined; a?: undefined; b: number; }
>y : number | undefined

d1.pos.a;
>d1.pos.a : string | undefined
>d1.pos : { b?: undefined; a?: undefined; x: number; y: number; } | { b?: undefined; x?: undefined; y?: undefined; a: string; } | { a?: undefined; x?: undefined; y?: undefined; b: number; }
>d1 : { kind: string; pos: { b?: undefined; a?: undefined; x: number; y: number; }; } | { kind: string; pos: { b?: undefined; x?: undefined; y?: undefined; a: string; } | { a?: undefined; x?: undefined; y?: undefined; b: number; }; }
>pos : { b?: undefined; a?: undefined; x: number; y: number; } | { b?: undefined; x?: undefined; y?: undefined; a: string; } | { a?: undefined; x?: undefined; y?: undefined; b: number; }
>d1.pos : { x: number; y: number; a?: undefined; b?: undefined; } | { x?: undefined; y?: undefined; a: string; b?: undefined; } | { x?: undefined; y?: undefined; a?: undefined; b: number; }
>d1 : { kind: string; pos: { x: number; y: number; a?: undefined; b?: undefined; }; } | { kind: string; pos: { x?: undefined; y?: undefined; a: string; b?: undefined; } | { x?: undefined; y?: undefined; a?: undefined; b: number; }; }
>pos : { x: number; y: number; a?: undefined; b?: undefined; } | { x?: undefined; y?: undefined; a: string; b?: undefined; } | { x?: undefined; y?: undefined; a?: undefined; b: number; }
>a : string | undefined

d1.pos.b;
>d1.pos.b : number | undefined
>d1.pos : { b?: undefined; a?: undefined; x: number; y: number; } | { b?: undefined; x?: undefined; y?: undefined; a: string; } | { a?: undefined; x?: undefined; y?: undefined; b: number; }
>d1 : { kind: string; pos: { b?: undefined; a?: undefined; x: number; y: number; }; } | { kind: string; pos: { b?: undefined; x?: undefined; y?: undefined; a: string; } | { a?: undefined; x?: undefined; y?: undefined; b: number; }; }
>pos : { b?: undefined; a?: undefined; x: number; y: number; } | { b?: undefined; x?: undefined; y?: undefined; a: string; } | { a?: undefined; x?: undefined; y?: undefined; b: number; }
>d1.pos : { x: number; y: number; a?: undefined; b?: undefined; } | { x?: undefined; y?: undefined; a: string; b?: undefined; } | { x?: undefined; y?: undefined; a?: undefined; b: number; }
>d1 : { kind: string; pos: { x: number; y: number; a?: undefined; b?: undefined; }; } | { kind: string; pos: { x?: undefined; y?: undefined; a: string; b?: undefined; } | { x?: undefined; y?: undefined; a?: undefined; b: number; }; }
>pos : { x: number; y: number; a?: undefined; b?: undefined; } | { x?: undefined; y?: undefined; a: string; b?: undefined; } | { x?: undefined; y?: undefined; a?: undefined; b: number; }
>b : number | undefined

declare function f<T>(...items: T[]): T;
Expand Down Expand Up @@ -292,8 +292,8 @@ let e1 = f({ a: 1, b: 2 }, { a: "abc" }, {});
>{} : {}

let e2 = f({}, { a: "abc" }, { a: 1, b: 2 });
>e2 : { b?: undefined; a?: undefined; } | { b?: undefined; a: string; } | { a: number; b: number; }
>f({}, { a: "abc" }, { a: 1, b: 2 }) : { b?: undefined; a?: undefined; } | { b?: undefined; a: string; } | { a: number; b: number; }
>e2 : { a?: undefined; b?: undefined; } | { a: string; b?: undefined; } | { a: number; b: number; }
>f({}, { a: "abc" }, { a: 1, b: 2 }) : { a?: undefined; b?: undefined; } | { a: string; b?: undefined; } | { a: number; b: number; }
>f : <T>(...items: T[]) => T
>{} : {}
>{ a: "abc" } : { a: string; }
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
// @strict: true
// @declaration: true
// @emitDeclarationOnly: true
export const a = Math.random() > 0.5 ? { user: 1 } : { status: "a" };
export const b = Math.random() > 0.5 ? { status: "no" } : { status: "ok", user: 2 };
Loading