Skip to content
Closed
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
11 changes: 7 additions & 4 deletions src/compiler/checker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15583,8 +15583,8 @@ namespace ts {
target = getUnionType(targets);
}
else {
if (inferFromMatchingType(source, (<UnionType>target).types, isTypeOrBaseIdenticalTo)) return;
if (inferFromMatchingType(source, (<UnionType>target).types, isTypeCloselyMatchedBy)) return;
if (inferFromMatchingType(source, (<UnionType>target).types, isTypeOrBaseIdenticalTo, /*continueOnNoInference*/ true)) return;
if (inferFromMatchingType(source, (<UnionType>target).types, isTypeCloselyMatchedBy, /*continueOnNoInference*/ true)) return;
}
}
else if (target.flags & TypeFlags.Intersection && some((<IntersectionType>target).types, t => !!getInferenceInfoForType(t))) {
Expand Down Expand Up @@ -15753,12 +15753,15 @@ namespace ts {
inferencePriority = Math.min(inferencePriority, saveInferencePriority);
}

function inferFromMatchingType(source: Type, targets: Type[], matches: (s: Type, t: Type) => boolean) {
function inferFromMatchingType(source: Type, targets: Type[], matches: (s: Type, t: Type) => boolean, continueOnNoInference?: boolean) {
let matched = false;
for (const t of targets) {
if (matches(source, t)) {
const currPri = inferencePriority;
inferFromTypes(source, t);
matched = true;
if (!continueOnNoInference || inferencePriority < currPri) {
matched = true;
}
}
}
return matched;
Expand Down
24 changes: 24 additions & 0 deletions tests/baselines/reference/observableInferenceCanBeMade.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
//// [observableInferenceCanBeMade.ts]
declare function of<T>(a: T): Observable<T>;
declare function from<O extends ObservableInput<any>>(input: O): Observable<ObservedValueOf<O>>;

type ObservedValueOf<O> = O extends ObservableInput<infer T> ? T : never;

interface Subscribable<T> {
subscribe(next?: (value: T) => void, error?: (error: any) => void, complete?: () => void): void;
}
type ObservableInput<T> = Subscribable<T> | Subscribable<never>;


declare class Observable<T> implements Subscribable<T> {
subscribe(next?: (value: T) => void, error?: (error: any) => void, complete?: () => void): void;
}

function asObservable(input: string | ObservableInput<string>): Observable<string> {
return typeof input === 'string' ? of(input) : from(input)
}

//// [observableInferenceCanBeMade.js]
function asObservable(input) {
return typeof input === 'string' ? of(input) : from(input);
}
77 changes: 77 additions & 0 deletions tests/baselines/reference/observableInferenceCanBeMade.symbols
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
=== tests/cases/compiler/observableInferenceCanBeMade.ts ===
declare function of<T>(a: T): Observable<T>;
>of : Symbol(of, Decl(observableInferenceCanBeMade.ts, 0, 0))
>T : Symbol(T, Decl(observableInferenceCanBeMade.ts, 0, 20))
>a : Symbol(a, Decl(observableInferenceCanBeMade.ts, 0, 23))
>T : Symbol(T, Decl(observableInferenceCanBeMade.ts, 0, 20))
>Observable : Symbol(Observable, Decl(observableInferenceCanBeMade.ts, 8, 64))
>T : Symbol(T, Decl(observableInferenceCanBeMade.ts, 0, 20))

declare function from<O extends ObservableInput<any>>(input: O): Observable<ObservedValueOf<O>>;
>from : Symbol(from, Decl(observableInferenceCanBeMade.ts, 0, 44))
>O : Symbol(O, Decl(observableInferenceCanBeMade.ts, 1, 22))
>ObservableInput : Symbol(ObservableInput, Decl(observableInferenceCanBeMade.ts, 7, 1))
>input : Symbol(input, Decl(observableInferenceCanBeMade.ts, 1, 54))
>O : Symbol(O, Decl(observableInferenceCanBeMade.ts, 1, 22))
>Observable : Symbol(Observable, Decl(observableInferenceCanBeMade.ts, 8, 64))
>ObservedValueOf : Symbol(ObservedValueOf, Decl(observableInferenceCanBeMade.ts, 1, 96))
>O : Symbol(O, Decl(observableInferenceCanBeMade.ts, 1, 22))

type ObservedValueOf<O> = O extends ObservableInput<infer T> ? T : never;
>ObservedValueOf : Symbol(ObservedValueOf, Decl(observableInferenceCanBeMade.ts, 1, 96))
>O : Symbol(O, Decl(observableInferenceCanBeMade.ts, 3, 21))
>O : Symbol(O, Decl(observableInferenceCanBeMade.ts, 3, 21))
>ObservableInput : Symbol(ObservableInput, Decl(observableInferenceCanBeMade.ts, 7, 1))
>T : Symbol(T, Decl(observableInferenceCanBeMade.ts, 3, 57))
>T : Symbol(T, Decl(observableInferenceCanBeMade.ts, 3, 57))

interface Subscribable<T> {
>Subscribable : Symbol(Subscribable, Decl(observableInferenceCanBeMade.ts, 3, 73))
>T : Symbol(T, Decl(observableInferenceCanBeMade.ts, 5, 23))

subscribe(next?: (value: T) => void, error?: (error: any) => void, complete?: () => void): void;
>subscribe : Symbol(Subscribable.subscribe, Decl(observableInferenceCanBeMade.ts, 5, 27))
>next : Symbol(next, Decl(observableInferenceCanBeMade.ts, 6, 14))
>value : Symbol(value, Decl(observableInferenceCanBeMade.ts, 6, 22))
>T : Symbol(T, Decl(observableInferenceCanBeMade.ts, 5, 23))
>error : Symbol(error, Decl(observableInferenceCanBeMade.ts, 6, 40))
>error : Symbol(error, Decl(observableInferenceCanBeMade.ts, 6, 50))
>complete : Symbol(complete, Decl(observableInferenceCanBeMade.ts, 6, 70))
}
type ObservableInput<T> = Subscribable<T> | Subscribable<never>;
>ObservableInput : Symbol(ObservableInput, Decl(observableInferenceCanBeMade.ts, 7, 1))
>T : Symbol(T, Decl(observableInferenceCanBeMade.ts, 8, 21))
>Subscribable : Symbol(Subscribable, Decl(observableInferenceCanBeMade.ts, 3, 73))
>T : Symbol(T, Decl(observableInferenceCanBeMade.ts, 8, 21))
>Subscribable : Symbol(Subscribable, Decl(observableInferenceCanBeMade.ts, 3, 73))


declare class Observable<T> implements Subscribable<T> {
>Observable : Symbol(Observable, Decl(observableInferenceCanBeMade.ts, 8, 64))
>T : Symbol(T, Decl(observableInferenceCanBeMade.ts, 11, 25))
>Subscribable : Symbol(Subscribable, Decl(observableInferenceCanBeMade.ts, 3, 73))
>T : Symbol(T, Decl(observableInferenceCanBeMade.ts, 11, 25))

subscribe(next?: (value: T) => void, error?: (error: any) => void, complete?: () => void): void;
>subscribe : Symbol(Observable.subscribe, Decl(observableInferenceCanBeMade.ts, 11, 56))
>next : Symbol(next, Decl(observableInferenceCanBeMade.ts, 12, 14))
>value : Symbol(value, Decl(observableInferenceCanBeMade.ts, 12, 22))
>T : Symbol(T, Decl(observableInferenceCanBeMade.ts, 11, 25))
>error : Symbol(error, Decl(observableInferenceCanBeMade.ts, 12, 40))
>error : Symbol(error, Decl(observableInferenceCanBeMade.ts, 12, 50))
>complete : Symbol(complete, Decl(observableInferenceCanBeMade.ts, 12, 70))
}

function asObservable(input: string | ObservableInput<string>): Observable<string> {
>asObservable : Symbol(asObservable, Decl(observableInferenceCanBeMade.ts, 13, 1))
>input : Symbol(input, Decl(observableInferenceCanBeMade.ts, 15, 22))
>ObservableInput : Symbol(ObservableInput, Decl(observableInferenceCanBeMade.ts, 7, 1))
>Observable : Symbol(Observable, Decl(observableInferenceCanBeMade.ts, 8, 64))

return typeof input === 'string' ? of(input) : from(input)
>input : Symbol(input, Decl(observableInferenceCanBeMade.ts, 15, 22))
>of : Symbol(of, Decl(observableInferenceCanBeMade.ts, 0, 0))
>input : Symbol(input, Decl(observableInferenceCanBeMade.ts, 15, 22))
>from : Symbol(from, Decl(observableInferenceCanBeMade.ts, 0, 44))
>input : Symbol(input, Decl(observableInferenceCanBeMade.ts, 15, 22))
}
54 changes: 54 additions & 0 deletions tests/baselines/reference/observableInferenceCanBeMade.types
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
=== tests/cases/compiler/observableInferenceCanBeMade.ts ===
declare function of<T>(a: T): Observable<T>;
>of : <T>(a: T) => Observable<T>
>a : T

declare function from<O extends ObservableInput<any>>(input: O): Observable<ObservedValueOf<O>>;
>from : <O extends ObservableInput<any>>(input: O) => Observable<ObservedValueOf<O>>
>input : O

type ObservedValueOf<O> = O extends ObservableInput<infer T> ? T : never;
>ObservedValueOf : ObservedValueOf<O>

interface Subscribable<T> {
subscribe(next?: (value: T) => void, error?: (error: any) => void, complete?: () => void): void;
>subscribe : (next?: (value: T) => void, error?: (error: any) => void, complete?: () => void) => void
>next : (value: T) => void
>value : T
>error : (error: any) => void
>error : any
>complete : () => void
}
type ObservableInput<T> = Subscribable<T> | Subscribable<never>;
>ObservableInput : ObservableInput<T>


declare class Observable<T> implements Subscribable<T> {
>Observable : Observable<T>

subscribe(next?: (value: T) => void, error?: (error: any) => void, complete?: () => void): void;
>subscribe : (next?: (value: T) => void, error?: (error: any) => void, complete?: () => void) => void
>next : (value: T) => void
>value : T
>error : (error: any) => void
>error : any
>complete : () => void
}

function asObservable(input: string | ObservableInput<string>): Observable<string> {
>asObservable : (input: string | Subscribable<never> | Subscribable<string>) => Observable<string>
>input : string | Subscribable<never> | Subscribable<string>

return typeof input === 'string' ? of(input) : from(input)
>typeof input === 'string' ? of(input) : from(input) : Observable<string>
>typeof input === 'string' : boolean
>typeof input : "string" | "number" | "bigint" | "boolean" | "symbol" | "undefined" | "object" | "function"
>input : string | Subscribable<never> | Subscribable<string>
>'string' : "string"
>of(input) : Observable<string>
>of : <T>(a: T) => Observable<T>
>input : string
>from(input) : Observable<string>
>from : <O extends ObservableInput<any>>(input: O) => Observable<ObservedValueOf<O>>
>input : ObservableInput<string>
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ var e1: number | string | boolean;
>e1 : string | number | boolean

f1(a1); // string
>f1(a1) : unknown
>f1(a1) : string
>f1 : <T>(x: string | T) => T
>a1 : string

Expand Down
12 changes: 6 additions & 6 deletions tests/baselines/reference/unionTypeInference.types
Original file line number Diff line number Diff line change
Expand Up @@ -35,15 +35,15 @@ const a3 = f1(1, sn); // number
>sn : string | number

const a4 = f1(undefined, "abc"); // undefined
>a4 : undefined
>f1(undefined, "abc") : undefined
>a4 : "abc" | undefined
>f1(undefined, "abc") : "abc" | undefined
>f1 : <T>(x: T, y: string | T) => T
>undefined : undefined
>"abc" : "abc"

const a5 = f1("foo", "bar"); // "foo"
>a5 : "foo"
>f1("foo", "bar") : "foo"
>a5 : "foo" | "bar"
>f1("foo", "bar") : "foo" | "bar"
>f1 : <T>(x: T, y: string | T) => T
>"foo" : "foo"
>"bar" : "bar"
Expand Down Expand Up @@ -104,8 +104,8 @@ const c4 = f3(b); // true
>b : boolean

const c5 = f3("abc"); // never
>c5 : unknown
>f3("abc") : unknown
>c5 : "abc"
>f3("abc") : "abc"
>f3 : <T>(x: string | false | T) => T
>"abc" : "abc"

Expand Down
18 changes: 18 additions & 0 deletions tests/cases/compiler/observableInferenceCanBeMade.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
declare function of<T>(a: T): Observable<T>;
declare function from<O extends ObservableInput<any>>(input: O): Observable<ObservedValueOf<O>>;

type ObservedValueOf<O> = O extends ObservableInput<infer T> ? T : never;

interface Subscribable<T> {
subscribe(next?: (value: T) => void, error?: (error: any) => void, complete?: () => void): void;
}
type ObservableInput<T> = Subscribable<T> | Subscribable<never>;


declare class Observable<T> implements Subscribable<T> {
subscribe(next?: (value: T) => void, error?: (error: any) => void, complete?: () => void): void;
}

function asObservable(input: string | ObservableInput<string>): Observable<string> {
return typeof input === 'string' ? of(input) : from(input)
}
2 changes: 1 addition & 1 deletion tests/cases/user/puppeteer/puppeteer