Skip to content

Forbid inferences to conditional type branches at contravariant positions #30287

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Mar 11, 2019
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 src/compiler/checker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14662,7 +14662,7 @@ namespace ts {
inferFromTypes(getTrueTypeFromConditionalType(<ConditionalType>source), getTrueTypeFromConditionalType(<ConditionalType>target));
inferFromTypes(getFalseTypeFromConditionalType(<ConditionalType>source), getFalseTypeFromConditionalType(<ConditionalType>target));
}
else if (target.flags & TypeFlags.Conditional) {
else if (target.flags & TypeFlags.Conditional && !contravariant) {
inferFromTypes(source, getTrueTypeFromConditionalType(<ConditionalType>target));
inferFromTypes(source, getFalseTypeFromConditionalType(<ConditionalType>target));
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
//// [overloadedConstructorFixesInferencesAppropriately.ts]
interface Box<T> {
v: T;
}

interface ErrorResult {
readonly error: true
}

interface AsyncLoaderProps<TResult extends {}> {
readonly asyncLoad: () => Box<TResult>;
readonly children: (result: Exclude<TResult, ErrorResult>) => string;
}

class AsyncLoader<TResult extends {}> {
constructor(props: string, context: any);
constructor(props: AsyncLoaderProps<TResult>);
constructor(...args: any[]) {}
}

function load(): Box<{ success: true } | ErrorResult> {
return null as any;
}

new AsyncLoader({
asyncLoad: load,
children: result => result.success as any,
}); // should work fine


//// [overloadedConstructorFixesInferencesAppropriately.js]
"use strict";
var AsyncLoader = /** @class */ (function () {
function AsyncLoader() {
var args = [];
for (var _i = 0; _i < arguments.length; _i++) {
args[_i] = arguments[_i];
}
}
return AsyncLoader;
}());
function load() {
return null;
}
new AsyncLoader({
asyncLoad: load,
children: function (result) { return result.success; }
}); // should work fine
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
=== tests/cases/compiler/overloadedConstructorFixesInferencesAppropriately.ts ===
interface Box<T> {
>Box : Symbol(Box, Decl(overloadedConstructorFixesInferencesAppropriately.ts, 0, 0))
>T : Symbol(T, Decl(overloadedConstructorFixesInferencesAppropriately.ts, 0, 14))

v: T;
>v : Symbol(Box.v, Decl(overloadedConstructorFixesInferencesAppropriately.ts, 0, 18))
>T : Symbol(T, Decl(overloadedConstructorFixesInferencesAppropriately.ts, 0, 14))
}

interface ErrorResult {
>ErrorResult : Symbol(ErrorResult, Decl(overloadedConstructorFixesInferencesAppropriately.ts, 2, 1))

readonly error: true
>error : Symbol(ErrorResult.error, Decl(overloadedConstructorFixesInferencesAppropriately.ts, 4, 23))
}

interface AsyncLoaderProps<TResult extends {}> {
>AsyncLoaderProps : Symbol(AsyncLoaderProps, Decl(overloadedConstructorFixesInferencesAppropriately.ts, 6, 1))
>TResult : Symbol(TResult, Decl(overloadedConstructorFixesInferencesAppropriately.ts, 8, 27))

readonly asyncLoad: () => Box<TResult>;
>asyncLoad : Symbol(AsyncLoaderProps.asyncLoad, Decl(overloadedConstructorFixesInferencesAppropriately.ts, 8, 48))
>Box : Symbol(Box, Decl(overloadedConstructorFixesInferencesAppropriately.ts, 0, 0))
>TResult : Symbol(TResult, Decl(overloadedConstructorFixesInferencesAppropriately.ts, 8, 27))

readonly children: (result: Exclude<TResult, ErrorResult>) => string;
>children : Symbol(AsyncLoaderProps.children, Decl(overloadedConstructorFixesInferencesAppropriately.ts, 9, 43))
>result : Symbol(result, Decl(overloadedConstructorFixesInferencesAppropriately.ts, 10, 24))
>Exclude : Symbol(Exclude, Decl(lib.es5.d.ts, --, --))
>TResult : Symbol(TResult, Decl(overloadedConstructorFixesInferencesAppropriately.ts, 8, 27))
>ErrorResult : Symbol(ErrorResult, Decl(overloadedConstructorFixesInferencesAppropriately.ts, 2, 1))
}

class AsyncLoader<TResult extends {}> {
>AsyncLoader : Symbol(AsyncLoader, Decl(overloadedConstructorFixesInferencesAppropriately.ts, 11, 1))
>TResult : Symbol(TResult, Decl(overloadedConstructorFixesInferencesAppropriately.ts, 13, 18))

constructor(props: string, context: any);
>props : Symbol(props, Decl(overloadedConstructorFixesInferencesAppropriately.ts, 14, 16))
>context : Symbol(context, Decl(overloadedConstructorFixesInferencesAppropriately.ts, 14, 30))

constructor(props: AsyncLoaderProps<TResult>);
>props : Symbol(props, Decl(overloadedConstructorFixesInferencesAppropriately.ts, 15, 16))
>AsyncLoaderProps : Symbol(AsyncLoaderProps, Decl(overloadedConstructorFixesInferencesAppropriately.ts, 6, 1))
>TResult : Symbol(TResult, Decl(overloadedConstructorFixesInferencesAppropriately.ts, 13, 18))

constructor(...args: any[]) {}
>args : Symbol(args, Decl(overloadedConstructorFixesInferencesAppropriately.ts, 16, 16))
}

function load(): Box<{ success: true } | ErrorResult> {
>load : Symbol(load, Decl(overloadedConstructorFixesInferencesAppropriately.ts, 17, 1))
>Box : Symbol(Box, Decl(overloadedConstructorFixesInferencesAppropriately.ts, 0, 0))
>success : Symbol(success, Decl(overloadedConstructorFixesInferencesAppropriately.ts, 19, 22))
>ErrorResult : Symbol(ErrorResult, Decl(overloadedConstructorFixesInferencesAppropriately.ts, 2, 1))

return null as any;
}

new AsyncLoader({
>AsyncLoader : Symbol(AsyncLoader, Decl(overloadedConstructorFixesInferencesAppropriately.ts, 11, 1))

asyncLoad: load,
>asyncLoad : Symbol(asyncLoad, Decl(overloadedConstructorFixesInferencesAppropriately.ts, 23, 17))
>load : Symbol(load, Decl(overloadedConstructorFixesInferencesAppropriately.ts, 17, 1))

children: result => result.success as any,
>children : Symbol(children, Decl(overloadedConstructorFixesInferencesAppropriately.ts, 24, 20))
>result : Symbol(result, Decl(overloadedConstructorFixesInferencesAppropriately.ts, 25, 13))
>result.success : Symbol(success, Decl(overloadedConstructorFixesInferencesAppropriately.ts, 19, 22))
>result : Symbol(result, Decl(overloadedConstructorFixesInferencesAppropriately.ts, 25, 13))
>success : Symbol(success, Decl(overloadedConstructorFixesInferencesAppropriately.ts, 19, 22))

}); // should work fine

Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
=== tests/cases/compiler/overloadedConstructorFixesInferencesAppropriately.ts ===
interface Box<T> {
v: T;
>v : T
}

interface ErrorResult {
readonly error: true
>error : true
>true : true
}

interface AsyncLoaderProps<TResult extends {}> {
readonly asyncLoad: () => Box<TResult>;
>asyncLoad : () => Box<TResult>

readonly children: (result: Exclude<TResult, ErrorResult>) => string;
>children : (result: Exclude<TResult, ErrorResult>) => string
>result : Exclude<TResult, ErrorResult>
}

class AsyncLoader<TResult extends {}> {
>AsyncLoader : AsyncLoader<TResult>

constructor(props: string, context: any);
>props : string
>context : any

constructor(props: AsyncLoaderProps<TResult>);
>props : AsyncLoaderProps<TResult>

constructor(...args: any[]) {}
>args : any[]
}

function load(): Box<{ success: true } | ErrorResult> {
>load : () => Box<ErrorResult | { success: true; }>
>success : true
>true : true

return null as any;
>null as any : any
>null : null
}

new AsyncLoader({
>new AsyncLoader({ asyncLoad: load, children: result => result.success as any,}) : AsyncLoader<ErrorResult | { success: true; }>
>AsyncLoader : typeof AsyncLoader
>{ asyncLoad: load, children: result => result.success as any,} : { asyncLoad: () => Box<ErrorResult | { success: true; }>; children: (result: { success: true; }) => any; }

asyncLoad: load,
>asyncLoad : () => Box<ErrorResult | { success: true; }>
>load : () => Box<ErrorResult | { success: true; }>

children: result => result.success as any,
>children : (result: { success: true; }) => any
>result => result.success as any : (result: { success: true; }) => any
>result : { success: true; }
>result.success as any : any
>result.success : true
>result : { success: true; }
>success : true

}); // should work fine

Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
// @strict: true
interface Box<T> {
v: T;
}

interface ErrorResult {
readonly error: true
}

interface AsyncLoaderProps<TResult extends {}> {
readonly asyncLoad: () => Box<TResult>;
readonly children: (result: Exclude<TResult, ErrorResult>) => string;
}

class AsyncLoader<TResult extends {}> {
constructor(props: string, context: any);
constructor(props: AsyncLoaderProps<TResult>);
constructor(...args: any[]) {}
}

function load(): Box<{ success: true } | ErrorResult> {
return null as any;
}

new AsyncLoader({
asyncLoad: load,
children: result => result.success as any,
}); // should work fine