Skip to content
Merged
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
2 changes: 1 addition & 1 deletion tsc/internal/checker/checker.go
Original file line number Diff line number Diff line change
Expand Up @@ -31281,7 +31281,7 @@ func (d *ObjectLiteralDiscriminator) name(index int) string {
return d.members[index-len(d.props)].Name()
}

func (d *ObjectLiteralDiscriminator) matches(index int, t *Type) bool {
func (d *ObjectLiteralDiscriminator) matches(index int, t *Type, _ bool) bool {
var propType *Type
if index < len(d.props) {
prop := d.props[index]
Expand Down
4 changes: 2 additions & 2 deletions tsc/internal/checker/inference.go
Original file line number Diff line number Diff line change
Expand Up @@ -250,7 +250,7 @@ func (c *Checker) inferFromTypes(n *InferenceState, source *Type, target *Type)
c.inferToUnionOrIntersectionType(n, source, target)
case source.flags&TypeFlagsUnion != 0:
if discriminants := c.getInferenceDiscriminants(source, target); len(discriminants) != 0 {
discriminator := &TypeDiscriminator{c: c, props: discriminants, reverse: true, isRelatedTo: c.compareTypesAssignableSimple}
discriminator := &TypeDiscriminator{c: c, props: discriminants, reverse: true, isRelatedTo: c.compareTypesComparableSimple}
source = c.discriminateTypeByDiscriminableItems(source, discriminator)
}
for _, sourceType := range source.Distributed() {
Expand Down Expand Up @@ -468,7 +468,7 @@ func (c *Checker) inferToUnionOrIntersectionType(n *InferenceState, source *Type
filteredTargetsBySource = make([][]*Type, len(sources))
for i, s := range sources {
if discriminants := c.getInferenceDiscriminants(target, s); len(discriminants) != 0 {
discriminator := &TypeDiscriminator{c: c, props: discriminants, isRelatedTo: c.compareTypesAssignableSimple}
discriminator := &TypeDiscriminator{c: c, props: discriminants, isRelatedTo: c.compareTypesComparableSimple}
if filtered := c.discriminateTypeByDiscriminableItems(target, discriminator); filtered != target {
filteredTargetsBySource[i] = filtered.Distributed()
}
Expand Down
32 changes: 26 additions & 6 deletions tsc/internal/checker/relater.go
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,13 @@ func (c *Checker) compareTypesAssignableSimple(source *Type, target *Type) Terna
return TernaryFalse
}

func (c *Checker) compareTypesComparableSimple(source *Type, target *Type) Ternary {
if c.isTypeRelatedTo(source, target, c.comparableRelation) {
return TernaryTrue
}
return TernaryFalse
}

func (c *Checker) compareTypesAssignableWorker(source *Type, target *Type, reportErrors bool) Ternary {
if c.isTypeRelatedTo(source, target, c.assignableRelation) {
return TernaryTrue
Expand Down Expand Up @@ -1042,7 +1049,12 @@ func (d *TypeDiscriminator) name(index int) string {
return d.props[index].Name()
}

func (d *TypeDiscriminator) matches(index int, t *Type) bool {
func (d *TypeDiscriminator) matches(index int, t *Type, isOptional bool) bool {
// Two optional discriminants always overlap through absence. Under strictNullChecks this is what the
// relation below would conclude anyway, so skip the property type resolution and the comparisons.
if isOptional && d.c.strictNullChecks && d.props[index].Flags()&ast.SymbolFlagsOptional != 0 {
return true
}
sourceType, targetType := d.c.getTypeOfSymbol(d.props[index]), t
if d.reverse {
sourceType, targetType = targetType, sourceType
Expand Down Expand Up @@ -1201,9 +1213,9 @@ func (c *Checker) mapTypesByKeyProperty(types []*Type, keyPropertyName string) m
}

type Discriminator interface {
len() int // Number of discriminant properties
name(index int) string // Property name of index-th discriminator
matches(index int, t *Type) bool // True if index-th discriminator matches the given type
len() int // Number of discriminant properties
name(index int) string // Property name of index-th discriminator
matches(index int, t *Type, isOptional bool) bool // True if index-th discriminator matches the given type, which is optional if isOptional is set
}

func (c *Checker) discriminateTypeByDiscriminableItems(target *Type, discriminator Discriminator) *Type {
Expand All @@ -1221,9 +1233,17 @@ func (c *Checker) discriminateTypeByDiscriminableItems(target *Type, discriminat
matched := false
for i := range types {
if include[i] != TernaryFalse {
targetType := c.getTypeOfPropertyOrIndexSignatureOfType(types[i], discriminator.name(n))
name := discriminator.name(n)
var targetType *Type
isOptional := false
if prop := c.getPropertyOfType(types[i], name); prop != nil {
targetType = c.getTypeOfSymbol(prop)
isOptional = prop.Flags()&ast.SymbolFlagsOptional != 0
} else if indexInfo := c.getApplicableIndexInfoForName(types[i], name); indexInfo != nil {
targetType = c.addOptionalityEx(indexInfo.valueType, true /*isProperty*/, true /*isOptional*/)
}
if targetType != nil {
if discriminator.matches(n, targetType) {
if discriminator.matches(n, targetType, isOptional) {
matched = true
} else {
include[i] = TernaryMaybe
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,13 +35,9 @@ inferenceDiscriminantOverlap.ts(39,5): error TS2322: Type '{ tag?: "a" | undefin
Types of property 'tag' are incompatible.
Type '"a" | undefined' is not assignable to type '"b" | undefined'.
Type '"a"' is not assignable to type '"b"'.
inferenceDiscriminantOverlap.ts(55,5): error TS2322: Type '{ kind: "a"; value: readonly []; }' is not assignable to type '{ kind: string; value: string[]; } | { kind: "a"; value: number; }'.
Type '{ kind: "a"; value: readonly []; }' is not assignable to type '{ kind: "a"; value: number; }'.
Types of property 'value' are incompatible.
Type 'readonly []' is not assignable to type 'number'.


==== inferenceDiscriminantOverlap.ts (9 errors) ====
==== inferenceDiscriminantOverlap.ts (8 errors) ====
declare const validOptionalSource: { tag: "a"; value: 1 } | { tag?: "a"; value: 2 };
declare const mixedOptionalSource: { tag: "a"; value: 1 } | { tag?: "b"; value: 2 };
declare const matchingOptionalSource: { tag: "a"; value: 1 } | { tag?: "a"; value: 2 } | { tag: "b"; value: 3 };
Expand Down Expand Up @@ -142,11 +138,6 @@ inferenceDiscriminantOverlap.ts(55,5): error TS2322: Type '{ kind: "a"; value: r

export function broadContext(): { kind: string; value: string[] } | { kind: "a"; value: number } {
return makeTagged([]);
~~~~~~
!!! error TS2322: Type '{ kind: "a"; value: readonly []; }' is not assignable to type '{ kind: string; value: string[]; } | { kind: "a"; value: number; }'.
!!! error TS2322: Type '{ kind: "a"; value: readonly []; }' is not assignable to type '{ kind: "a"; value: number; }'.
!!! error TS2322: Types of property 'value' are incompatible.
!!! error TS2322: Type 'readonly []' is not assignable to type 'number'.
}
export function partialTagContext(): { kind: "a" | "b"; value: string[] } | { kind: "a"; value: number } {
return makeTagged([]);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -257,7 +257,7 @@ export function broadContext(): { kind: string; value: string[] } | { kind: "a";
>value : number

return makeTagged([]);
>makeTagged([]) : { kind: "a"; value: readonly []; }
>makeTagged([]) : { kind: "a"; value: []; }
>makeTagged : <const T>(value: T) => { kind: "a"; value: T; }
>[] : []
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,18 +35,14 @@ inferenceDiscriminantOverlap.ts(39,5): error TS2375: Type '{ tag?: "a"; value: 1
Type '{ tag?: "a"; value: 1 | 2; }' is not assignable to type '{ tag?: "b"; value: 2; }' with 'exactOptionalPropertyTypes: true'. Consider adding 'undefined' to the types of the target's properties.
Types of property 'tag' are incompatible.
Type '"a"' is not assignable to type '"b"'.
inferenceDiscriminantOverlap.ts(55,5): error TS2322: Type '{ kind: "a"; value: readonly []; }' is not assignable to type '{ kind: string; value: string[]; } | { kind: "a"; value: number; }'.
Type '{ kind: "a"; value: readonly []; }' is not assignable to type '{ kind: "a"; value: number; }'.
Types of property 'value' are incompatible.
Type 'readonly []' is not assignable to type 'number'.
inferenceDiscriminantOverlap.ts(61,5): error TS2375: Type '{ kind: "a" | undefined; value: []; }' is not assignable to type '{ kind?: "a"; value: string[]; } | { kind: "a"; value: number; }' with 'exactOptionalPropertyTypes: true'. Consider adding 'undefined' to the types of the target's properties.
Type '{ kind: "a" | undefined; value: []; }' is not assignable to type '{ kind: "a"; value: number; }'.
Types of property 'kind' are incompatible.
Type '"a" | undefined' is not assignable to type '"a"'.
Type 'undefined' is not assignable to type '"a"'.


==== inferenceDiscriminantOverlap.ts (11 errors) ====
==== inferenceDiscriminantOverlap.ts (10 errors) ====
declare const validOptionalSource: { tag: "a"; value: 1 } | { tag?: "a"; value: 2 };
declare const mixedOptionalSource: { tag: "a"; value: 1 } | { tag?: "b"; value: 2 };
declare const matchingOptionalSource: { tag: "a"; value: 1 } | { tag?: "a"; value: 2 } | { tag: "b"; value: 3 };
Expand Down Expand Up @@ -148,11 +144,6 @@ inferenceDiscriminantOverlap.ts(61,5): error TS2375: Type '{ kind: "a" | undefin

export function broadContext(): { kind: string; value: string[] } | { kind: "a"; value: number } {
return makeTagged([]);
~~~~~~
!!! error TS2322: Type '{ kind: "a"; value: readonly []; }' is not assignable to type '{ kind: string; value: string[]; } | { kind: "a"; value: number; }'.
!!! error TS2322: Type '{ kind: "a"; value: readonly []; }' is not assignable to type '{ kind: "a"; value: number; }'.
!!! error TS2322: Types of property 'value' are incompatible.
!!! error TS2322: Type 'readonly []' is not assignable to type 'number'.
}
export function partialTagContext(): { kind: "a" | "b"; value: string[] } | { kind: "a"; value: number } {
return makeTagged([]);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -257,7 +257,7 @@ export function broadContext(): { kind: string; value: string[] } | { kind: "a";
>value : number

return makeTagged([]);
>makeTagged([]) : { kind: "a"; value: readonly []; }
>makeTagged([]) : { kind: "a"; value: []; }
>makeTagged : <const T>(value: T) => { kind: "a"; value: T; }
>[] : []
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@ inferenceDiscriminatedUnions1.ts(52,17): error TS2345: Argument of type '{ kind:
Type '{ kind: "b"; value: number; }' is not assignable to type '{ kind: "a"; value: string; }'.
Types of property 'kind' are incompatible.
Type '"b"' is not assignable to type '"a"'.
inferenceDiscriminatedUnions1.ts(53,17): error TS2345: Argument of type '{ kind: string; value: number; } | { kind: "a"; value: string; }' is not assignable to parameter of type '{ kind: "a"; value: string; }'.
Type '{ kind: string; value: number; }' is not assignable to type '{ kind: "a"; value: string; }'.
inferenceDiscriminatedUnions1.ts(53,17): error TS2345: Argument of type '{ kind: string; value: number; } | { kind: "a"; value: string; }' is not assignable to parameter of type '{ kind: "a"; value: number; }'.
Type '{ kind: string; value: number; }' is not assignable to type '{ kind: "a"; value: number; }'.
Types of property 'kind' are incompatible.
Type 'string' is not assignable to type '"a"'.
inferenceDiscriminatedUnions1.ts(54,26): error TS2345: Argument of type '{ kind: number; value: number; } | { kind: "a"; value: string; }' is not assignable to parameter of type '{ kind: "a"; value: string; }'.
Expand Down Expand Up @@ -121,8 +121,8 @@ inferenceDiscriminatedUnions1.ts(150,68): error TS2345: Argument of type '{ type
!!! error TS2345: Type '"b"' is not assignable to type '"a"'.
const r4 = pick(u2);
~~
!!! error TS2345: Argument of type '{ kind: string; value: number; } | { kind: "a"; value: string; }' is not assignable to parameter of type '{ kind: "a"; value: string; }'.
!!! error TS2345: Type '{ kind: string; value: number; }' is not assignable to type '{ kind: "a"; value: string; }'.
!!! error TS2345: Argument of type '{ kind: string; value: number; } | { kind: "a"; value: string; }' is not assignable to parameter of type '{ kind: "a"; value: number; }'.
!!! error TS2345: Type '{ kind: string; value: number; }' is not assignable to type '{ kind: "a"; value: number; }'.
!!! error TS2345: Types of property 'kind' are incompatible.
!!! error TS2345: Type 'string' is not assignable to type '"a"'.
const broadResult = pick(broadTag);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -252,8 +252,8 @@ const r3 = pick(u1);
>u1 : { kind: "b"; value: number; } | { kind: "a"; value: string; }

const r4 = pick(u2);
>r4 : string
>pick(u2) : string
>r4 : number
>pick(u2) : number
>pick : <T>(x: { kind: "a"; value: T; }) => T
>u2 : { kind: string; value: number; } | { kind: "a"; value: string; }

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@ inferenceDiscriminatedUnions1.ts(52,17): error TS2345: Argument of type '{ kind:
Type '{ kind: "b"; value: number; }' is not assignable to type '{ kind: "a"; value: string; }'.
Types of property 'kind' are incompatible.
Type '"b"' is not assignable to type '"a"'.
inferenceDiscriminatedUnions1.ts(53,17): error TS2345: Argument of type '{ kind: string; value: number; } | { kind: "a"; value: string; }' is not assignable to parameter of type '{ kind: "a"; value: string; }'.
Type '{ kind: string; value: number; }' is not assignable to type '{ kind: "a"; value: string; }'.
inferenceDiscriminatedUnions1.ts(53,17): error TS2345: Argument of type '{ kind: string; value: number; } | { kind: "a"; value: string; }' is not assignable to parameter of type '{ kind: "a"; value: number; }'.
Type '{ kind: string; value: number; }' is not assignable to type '{ kind: "a"; value: number; }'.
Types of property 'kind' are incompatible.
Type 'string' is not assignable to type '"a"'.
inferenceDiscriminatedUnions1.ts(54,26): error TS2345: Argument of type '{ kind: number; value: number; } | { kind: "a"; value: string; }' is not assignable to parameter of type '{ kind: "a"; value: string; }'.
Expand Down Expand Up @@ -121,8 +121,8 @@ inferenceDiscriminatedUnions1.ts(150,68): error TS2345: Argument of type '{ type
!!! error TS2345: Type '"b"' is not assignable to type '"a"'.
const r4 = pick(u2);
~~
!!! error TS2345: Argument of type '{ kind: string; value: number; } | { kind: "a"; value: string; }' is not assignable to parameter of type '{ kind: "a"; value: string; }'.
!!! error TS2345: Type '{ kind: string; value: number; }' is not assignable to type '{ kind: "a"; value: string; }'.
!!! error TS2345: Argument of type '{ kind: string; value: number; } | { kind: "a"; value: string; }' is not assignable to parameter of type '{ kind: "a"; value: number; }'.
!!! error TS2345: Type '{ kind: string; value: number; }' is not assignable to type '{ kind: "a"; value: number; }'.
!!! error TS2345: Types of property 'kind' are incompatible.
!!! error TS2345: Type 'string' is not assignable to type '"a"'.
const broadResult = pick(broadTag);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -252,8 +252,8 @@ const r3 = pick(u1);
>u1 : { kind: "b"; value: number; } | { kind: "a"; value: string; }

const r4 = pick(u2);
>r4 : string
>pick(u2) : string
>r4 : number
>pick(u2) : number
>pick : <T>(x: { kind: "a"; value: T; }) => T
>u2 : { kind: string; value: number; } | { kind: "a"; value: string; }

Expand Down