mirror of
https://github.com/microsoft/TypeScript.git
synced 2026-05-05 16:54:54 -05:00
Make a fresh empty object literal not a subtype of a type with an index signaure (#29975)
* Forbid inferable index checkign during subtype relationship checking * Merge object.values and object.entries overloads to work around subtype change * Invert subtype relationship between fresh empty objects and non-empty object types * Remvoe comment * Revert lib change * Remove trailing whitespace ffs
This commit is contained in:
@@ -12787,6 +12787,11 @@ namespace ts {
|
||||
else if (isReadonlyArrayType(target) ? isArrayType(source) || isTupleType(source) : isArrayType(target) && isTupleType(source) && !source.target.readonly) {
|
||||
return isRelatedTo(getIndexTypeOfType(source, IndexKind.Number) || anyType, getIndexTypeOfType(target, IndexKind.Number) || anyType, reportErrors);
|
||||
}
|
||||
// Consider a fresh empty object literal type "closed" under the subtype relationship - this way `{} <- {[idx: string]: any} <- fresh({})`
|
||||
// and not `{} <- fresh({}) <- {[idx: string]: any}`
|
||||
else if (relation === subtypeRelation && isEmptyObjectType(target) && getObjectFlags(target) & ObjectFlags.FreshLiteral && !isEmptyObjectType(source)) {
|
||||
return Ternary.False;
|
||||
}
|
||||
// Even if relationship doesn't hold for unions, intersections, or generic type references,
|
||||
// it may hold in a structural comparison.
|
||||
// In a check of the form X = A & B, we will have previously checked if A relates to X or B relates
|
||||
|
||||
@@ -0,0 +1,53 @@
|
||||
tests/cases/compiler/emptyObjectNotSubtypeOfIndexSignatureContainingObject1.ts(41,3): error TS2322: Type 'Dictionary<string>' is not assignable to type 'Record<string, Bar>'.
|
||||
Index signatures are incompatible.
|
||||
Type 'string' is not assignable to type 'Bar'.
|
||||
|
||||
|
||||
==== tests/cases/compiler/emptyObjectNotSubtypeOfIndexSignatureContainingObject1.ts (1 errors) ====
|
||||
// This should behave the same as emptyObjectNotSubtypeOfIndexSignatureContainingObject2.ts
|
||||
// Begin types from Lodash.
|
||||
interface Dictionary<T> {
|
||||
[index: string]: T;
|
||||
}
|
||||
|
||||
interface NumericDictionary<T> {
|
||||
[index: number]: T;
|
||||
}
|
||||
|
||||
type ObjectIterator<TObject, TResult> = (
|
||||
value: TObject[keyof TObject],
|
||||
key: string,
|
||||
collection: TObject
|
||||
) => TResult;
|
||||
|
||||
type DictionaryIterator<T, TResult> = ObjectIterator<Dictionary<T>, TResult>;
|
||||
|
||||
// In lodash.d.ts this function has many overloads, but this seems to be the problematic one.
|
||||
function mapValues<T, TResult>(
|
||||
obj: Dictionary<T> | NumericDictionary<T> | null | undefined,
|
||||
callback: DictionaryIterator<T, TResult>
|
||||
): Dictionary<TResult> {
|
||||
return null as any;
|
||||
}
|
||||
// End types from Lodash.
|
||||
|
||||
interface Foo {
|
||||
foo: string;
|
||||
}
|
||||
|
||||
interface Bar {
|
||||
bar: string;
|
||||
}
|
||||
|
||||
export function fooToBar(
|
||||
foos: Record<string, Foo>
|
||||
): Record<string, Bar | null> {
|
||||
const result = foos == null ? {} : mapValues(foos, f => f.foo);
|
||||
// This line _should_ fail, because `result` is not the right type.
|
||||
return result;
|
||||
~~~~~~~~~~~~~~
|
||||
!!! error TS2322: Type 'Dictionary<string>' is not assignable to type 'Record<string, Bar>'.
|
||||
!!! error TS2322: Index signatures are incompatible.
|
||||
!!! error TS2322: Type 'string' is not assignable to type 'Bar'.
|
||||
}
|
||||
|
||||
@@ -0,0 +1,58 @@
|
||||
//// [emptyObjectNotSubtypeOfIndexSignatureContainingObject1.ts]
|
||||
// This should behave the same as emptyObjectNotSubtypeOfIndexSignatureContainingObject2.ts
|
||||
// Begin types from Lodash.
|
||||
interface Dictionary<T> {
|
||||
[index: string]: T;
|
||||
}
|
||||
|
||||
interface NumericDictionary<T> {
|
||||
[index: number]: T;
|
||||
}
|
||||
|
||||
type ObjectIterator<TObject, TResult> = (
|
||||
value: TObject[keyof TObject],
|
||||
key: string,
|
||||
collection: TObject
|
||||
) => TResult;
|
||||
|
||||
type DictionaryIterator<T, TResult> = ObjectIterator<Dictionary<T>, TResult>;
|
||||
|
||||
// In lodash.d.ts this function has many overloads, but this seems to be the problematic one.
|
||||
function mapValues<T, TResult>(
|
||||
obj: Dictionary<T> | NumericDictionary<T> | null | undefined,
|
||||
callback: DictionaryIterator<T, TResult>
|
||||
): Dictionary<TResult> {
|
||||
return null as any;
|
||||
}
|
||||
// End types from Lodash.
|
||||
|
||||
interface Foo {
|
||||
foo: string;
|
||||
}
|
||||
|
||||
interface Bar {
|
||||
bar: string;
|
||||
}
|
||||
|
||||
export function fooToBar(
|
||||
foos: Record<string, Foo>
|
||||
): Record<string, Bar | null> {
|
||||
const result = foos == null ? {} : mapValues(foos, f => f.foo);
|
||||
// This line _should_ fail, because `result` is not the right type.
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
//// [emptyObjectNotSubtypeOfIndexSignatureContainingObject1.js]
|
||||
"use strict";
|
||||
exports.__esModule = true;
|
||||
// In lodash.d.ts this function has many overloads, but this seems to be the problematic one.
|
||||
function mapValues(obj, callback) {
|
||||
return null;
|
||||
}
|
||||
function fooToBar(foos) {
|
||||
var result = foos == null ? {} : mapValues(foos, function (f) { return f.foo; });
|
||||
// This line _should_ fail, because `result` is not the right type.
|
||||
return result;
|
||||
}
|
||||
exports.fooToBar = fooToBar;
|
||||
@@ -0,0 +1,118 @@
|
||||
=== tests/cases/compiler/emptyObjectNotSubtypeOfIndexSignatureContainingObject1.ts ===
|
||||
// This should behave the same as emptyObjectNotSubtypeOfIndexSignatureContainingObject2.ts
|
||||
// Begin types from Lodash.
|
||||
interface Dictionary<T> {
|
||||
>Dictionary : Symbol(Dictionary, Decl(emptyObjectNotSubtypeOfIndexSignatureContainingObject1.ts, 0, 0))
|
||||
>T : Symbol(T, Decl(emptyObjectNotSubtypeOfIndexSignatureContainingObject1.ts, 2, 21))
|
||||
|
||||
[index: string]: T;
|
||||
>index : Symbol(index, Decl(emptyObjectNotSubtypeOfIndexSignatureContainingObject1.ts, 3, 3))
|
||||
>T : Symbol(T, Decl(emptyObjectNotSubtypeOfIndexSignatureContainingObject1.ts, 2, 21))
|
||||
}
|
||||
|
||||
interface NumericDictionary<T> {
|
||||
>NumericDictionary : Symbol(NumericDictionary, Decl(emptyObjectNotSubtypeOfIndexSignatureContainingObject1.ts, 4, 1))
|
||||
>T : Symbol(T, Decl(emptyObjectNotSubtypeOfIndexSignatureContainingObject1.ts, 6, 28))
|
||||
|
||||
[index: number]: T;
|
||||
>index : Symbol(index, Decl(emptyObjectNotSubtypeOfIndexSignatureContainingObject1.ts, 7, 3))
|
||||
>T : Symbol(T, Decl(emptyObjectNotSubtypeOfIndexSignatureContainingObject1.ts, 6, 28))
|
||||
}
|
||||
|
||||
type ObjectIterator<TObject, TResult> = (
|
||||
>ObjectIterator : Symbol(ObjectIterator, Decl(emptyObjectNotSubtypeOfIndexSignatureContainingObject1.ts, 8, 1))
|
||||
>TObject : Symbol(TObject, Decl(emptyObjectNotSubtypeOfIndexSignatureContainingObject1.ts, 10, 20))
|
||||
>TResult : Symbol(TResult, Decl(emptyObjectNotSubtypeOfIndexSignatureContainingObject1.ts, 10, 28))
|
||||
|
||||
value: TObject[keyof TObject],
|
||||
>value : Symbol(value, Decl(emptyObjectNotSubtypeOfIndexSignatureContainingObject1.ts, 10, 41))
|
||||
>TObject : Symbol(TObject, Decl(emptyObjectNotSubtypeOfIndexSignatureContainingObject1.ts, 10, 20))
|
||||
>TObject : Symbol(TObject, Decl(emptyObjectNotSubtypeOfIndexSignatureContainingObject1.ts, 10, 20))
|
||||
|
||||
key: string,
|
||||
>key : Symbol(key, Decl(emptyObjectNotSubtypeOfIndexSignatureContainingObject1.ts, 11, 32))
|
||||
|
||||
collection: TObject
|
||||
>collection : Symbol(collection, Decl(emptyObjectNotSubtypeOfIndexSignatureContainingObject1.ts, 12, 14))
|
||||
>TObject : Symbol(TObject, Decl(emptyObjectNotSubtypeOfIndexSignatureContainingObject1.ts, 10, 20))
|
||||
|
||||
) => TResult;
|
||||
>TResult : Symbol(TResult, Decl(emptyObjectNotSubtypeOfIndexSignatureContainingObject1.ts, 10, 28))
|
||||
|
||||
type DictionaryIterator<T, TResult> = ObjectIterator<Dictionary<T>, TResult>;
|
||||
>DictionaryIterator : Symbol(DictionaryIterator, Decl(emptyObjectNotSubtypeOfIndexSignatureContainingObject1.ts, 14, 13))
|
||||
>T : Symbol(T, Decl(emptyObjectNotSubtypeOfIndexSignatureContainingObject1.ts, 16, 24))
|
||||
>TResult : Symbol(TResult, Decl(emptyObjectNotSubtypeOfIndexSignatureContainingObject1.ts, 16, 26))
|
||||
>ObjectIterator : Symbol(ObjectIterator, Decl(emptyObjectNotSubtypeOfIndexSignatureContainingObject1.ts, 8, 1))
|
||||
>Dictionary : Symbol(Dictionary, Decl(emptyObjectNotSubtypeOfIndexSignatureContainingObject1.ts, 0, 0))
|
||||
>T : Symbol(T, Decl(emptyObjectNotSubtypeOfIndexSignatureContainingObject1.ts, 16, 24))
|
||||
>TResult : Symbol(TResult, Decl(emptyObjectNotSubtypeOfIndexSignatureContainingObject1.ts, 16, 26))
|
||||
|
||||
// In lodash.d.ts this function has many overloads, but this seems to be the problematic one.
|
||||
function mapValues<T, TResult>(
|
||||
>mapValues : Symbol(mapValues, Decl(emptyObjectNotSubtypeOfIndexSignatureContainingObject1.ts, 16, 77))
|
||||
>T : Symbol(T, Decl(emptyObjectNotSubtypeOfIndexSignatureContainingObject1.ts, 19, 19))
|
||||
>TResult : Symbol(TResult, Decl(emptyObjectNotSubtypeOfIndexSignatureContainingObject1.ts, 19, 21))
|
||||
|
||||
obj: Dictionary<T> | NumericDictionary<T> | null | undefined,
|
||||
>obj : Symbol(obj, Decl(emptyObjectNotSubtypeOfIndexSignatureContainingObject1.ts, 19, 31))
|
||||
>Dictionary : Symbol(Dictionary, Decl(emptyObjectNotSubtypeOfIndexSignatureContainingObject1.ts, 0, 0))
|
||||
>T : Symbol(T, Decl(emptyObjectNotSubtypeOfIndexSignatureContainingObject1.ts, 19, 19))
|
||||
>NumericDictionary : Symbol(NumericDictionary, Decl(emptyObjectNotSubtypeOfIndexSignatureContainingObject1.ts, 4, 1))
|
||||
>T : Symbol(T, Decl(emptyObjectNotSubtypeOfIndexSignatureContainingObject1.ts, 19, 19))
|
||||
|
||||
callback: DictionaryIterator<T, TResult>
|
||||
>callback : Symbol(callback, Decl(emptyObjectNotSubtypeOfIndexSignatureContainingObject1.ts, 20, 63))
|
||||
>DictionaryIterator : Symbol(DictionaryIterator, Decl(emptyObjectNotSubtypeOfIndexSignatureContainingObject1.ts, 14, 13))
|
||||
>T : Symbol(T, Decl(emptyObjectNotSubtypeOfIndexSignatureContainingObject1.ts, 19, 19))
|
||||
>TResult : Symbol(TResult, Decl(emptyObjectNotSubtypeOfIndexSignatureContainingObject1.ts, 19, 21))
|
||||
|
||||
): Dictionary<TResult> {
|
||||
>Dictionary : Symbol(Dictionary, Decl(emptyObjectNotSubtypeOfIndexSignatureContainingObject1.ts, 0, 0))
|
||||
>TResult : Symbol(TResult, Decl(emptyObjectNotSubtypeOfIndexSignatureContainingObject1.ts, 19, 21))
|
||||
|
||||
return null as any;
|
||||
}
|
||||
// End types from Lodash.
|
||||
|
||||
interface Foo {
|
||||
>Foo : Symbol(Foo, Decl(emptyObjectNotSubtypeOfIndexSignatureContainingObject1.ts, 24, 1))
|
||||
|
||||
foo: string;
|
||||
>foo : Symbol(Foo.foo, Decl(emptyObjectNotSubtypeOfIndexSignatureContainingObject1.ts, 27, 15))
|
||||
}
|
||||
|
||||
interface Bar {
|
||||
>Bar : Symbol(Bar, Decl(emptyObjectNotSubtypeOfIndexSignatureContainingObject1.ts, 29, 1))
|
||||
|
||||
bar: string;
|
||||
>bar : Symbol(Bar.bar, Decl(emptyObjectNotSubtypeOfIndexSignatureContainingObject1.ts, 31, 15))
|
||||
}
|
||||
|
||||
export function fooToBar(
|
||||
>fooToBar : Symbol(fooToBar, Decl(emptyObjectNotSubtypeOfIndexSignatureContainingObject1.ts, 33, 1))
|
||||
|
||||
foos: Record<string, Foo>
|
||||
>foos : Symbol(foos, Decl(emptyObjectNotSubtypeOfIndexSignatureContainingObject1.ts, 35, 25))
|
||||
>Record : Symbol(Record, Decl(lib.es5.d.ts, --, --))
|
||||
>Foo : Symbol(Foo, Decl(emptyObjectNotSubtypeOfIndexSignatureContainingObject1.ts, 24, 1))
|
||||
|
||||
): Record<string, Bar | null> {
|
||||
>Record : Symbol(Record, Decl(lib.es5.d.ts, --, --))
|
||||
>Bar : Symbol(Bar, Decl(emptyObjectNotSubtypeOfIndexSignatureContainingObject1.ts, 29, 1))
|
||||
|
||||
const result = foos == null ? {} : mapValues(foos, f => f.foo);
|
||||
>result : Symbol(result, Decl(emptyObjectNotSubtypeOfIndexSignatureContainingObject1.ts, 38, 7))
|
||||
>foos : Symbol(foos, Decl(emptyObjectNotSubtypeOfIndexSignatureContainingObject1.ts, 35, 25))
|
||||
>mapValues : Symbol(mapValues, Decl(emptyObjectNotSubtypeOfIndexSignatureContainingObject1.ts, 16, 77))
|
||||
>foos : Symbol(foos, Decl(emptyObjectNotSubtypeOfIndexSignatureContainingObject1.ts, 35, 25))
|
||||
>f : Symbol(f, Decl(emptyObjectNotSubtypeOfIndexSignatureContainingObject1.ts, 38, 52))
|
||||
>f.foo : Symbol(Foo.foo, Decl(emptyObjectNotSubtypeOfIndexSignatureContainingObject1.ts, 27, 15))
|
||||
>f : Symbol(f, Decl(emptyObjectNotSubtypeOfIndexSignatureContainingObject1.ts, 38, 52))
|
||||
>foo : Symbol(Foo.foo, Decl(emptyObjectNotSubtypeOfIndexSignatureContainingObject1.ts, 27, 15))
|
||||
|
||||
// This line _should_ fail, because `result` is not the right type.
|
||||
return result;
|
||||
>result : Symbol(result, Decl(emptyObjectNotSubtypeOfIndexSignatureContainingObject1.ts, 38, 7))
|
||||
}
|
||||
|
||||
@@ -0,0 +1,88 @@
|
||||
=== tests/cases/compiler/emptyObjectNotSubtypeOfIndexSignatureContainingObject1.ts ===
|
||||
// This should behave the same as emptyObjectNotSubtypeOfIndexSignatureContainingObject2.ts
|
||||
// Begin types from Lodash.
|
||||
interface Dictionary<T> {
|
||||
[index: string]: T;
|
||||
>index : string
|
||||
}
|
||||
|
||||
interface NumericDictionary<T> {
|
||||
[index: number]: T;
|
||||
>index : number
|
||||
}
|
||||
|
||||
type ObjectIterator<TObject, TResult> = (
|
||||
>ObjectIterator : ObjectIterator<TObject, TResult>
|
||||
|
||||
value: TObject[keyof TObject],
|
||||
>value : TObject[keyof TObject]
|
||||
|
||||
key: string,
|
||||
>key : string
|
||||
|
||||
collection: TObject
|
||||
>collection : TObject
|
||||
|
||||
) => TResult;
|
||||
|
||||
type DictionaryIterator<T, TResult> = ObjectIterator<Dictionary<T>, TResult>;
|
||||
>DictionaryIterator : ObjectIterator<Dictionary<T>, TResult>
|
||||
|
||||
// In lodash.d.ts this function has many overloads, but this seems to be the problematic one.
|
||||
function mapValues<T, TResult>(
|
||||
>mapValues : <T, TResult>(obj: Dictionary<T> | NumericDictionary<T>, callback: ObjectIterator<Dictionary<T>, TResult>) => Dictionary<TResult>
|
||||
|
||||
obj: Dictionary<T> | NumericDictionary<T> | null | undefined,
|
||||
>obj : Dictionary<T> | NumericDictionary<T>
|
||||
>null : null
|
||||
|
||||
callback: DictionaryIterator<T, TResult>
|
||||
>callback : ObjectIterator<Dictionary<T>, TResult>
|
||||
|
||||
): Dictionary<TResult> {
|
||||
return null as any;
|
||||
>null as any : any
|
||||
>null : null
|
||||
}
|
||||
// End types from Lodash.
|
||||
|
||||
interface Foo {
|
||||
foo: string;
|
||||
>foo : string
|
||||
}
|
||||
|
||||
interface Bar {
|
||||
bar: string;
|
||||
>bar : string
|
||||
}
|
||||
|
||||
export function fooToBar(
|
||||
>fooToBar : (foos: Record<string, Foo>) => Record<string, Bar>
|
||||
|
||||
foos: Record<string, Foo>
|
||||
>foos : Record<string, Foo>
|
||||
|
||||
): Record<string, Bar | null> {
|
||||
>null : null
|
||||
|
||||
const result = foos == null ? {} : mapValues(foos, f => f.foo);
|
||||
>result : Dictionary<string>
|
||||
>foos == null ? {} : mapValues(foos, f => f.foo) : Dictionary<string>
|
||||
>foos == null : boolean
|
||||
>foos : Record<string, Foo>
|
||||
>null : null
|
||||
>{} : {}
|
||||
>mapValues(foos, f => f.foo) : Dictionary<string>
|
||||
>mapValues : <T, TResult>(obj: Dictionary<T> | NumericDictionary<T>, callback: ObjectIterator<Dictionary<T>, TResult>) => Dictionary<TResult>
|
||||
>foos : Record<string, Foo>
|
||||
>f => f.foo : (f: Foo) => string
|
||||
>f : Foo
|
||||
>f.foo : string
|
||||
>f : Foo
|
||||
>foo : string
|
||||
|
||||
// This line _should_ fail, because `result` is not the right type.
|
||||
return result;
|
||||
>result : Dictionary<string>
|
||||
}
|
||||
|
||||
@@ -0,0 +1,54 @@
|
||||
tests/cases/compiler/emptyObjectNotSubtypeOfIndexSignatureContainingObject2.ts(42,3): error TS2322: Type 'Dictionary<string>' is not assignable to type 'Record<string, Bar>'.
|
||||
Index signatures are incompatible.
|
||||
Type 'string' is not assignable to type 'Bar'.
|
||||
|
||||
|
||||
==== tests/cases/compiler/emptyObjectNotSubtypeOfIndexSignatureContainingObject2.ts (1 errors) ====
|
||||
// This should behave the same as emptyObjectNotSubtypeOfIndexSignatureContainingObject1.ts
|
||||
// Begin types from Lodash.
|
||||
interface Dictionary<T> {
|
||||
[index: string]: T;
|
||||
}
|
||||
|
||||
interface NumericDictionary<T> {
|
||||
[index: number]: T;
|
||||
}
|
||||
|
||||
type ObjectIterator<TObject, TResult> = (
|
||||
value: TObject[keyof TObject],
|
||||
key: string,
|
||||
collection: TObject
|
||||
) => TResult;
|
||||
|
||||
type DictionaryIterator<T, TResult> = ObjectIterator<Dictionary<T>, TResult>;
|
||||
|
||||
// In lodash.d.ts this function has many overloads, but this seems to be the problematic one.
|
||||
function mapValues<T, TResult>(
|
||||
obj: Dictionary<T> | NumericDictionary<T> | null | undefined,
|
||||
callback: DictionaryIterator<T, TResult>
|
||||
): Dictionary<TResult> {
|
||||
return null as any;
|
||||
}
|
||||
// End types from Lodash.
|
||||
|
||||
interface Foo {
|
||||
foo: string;
|
||||
}
|
||||
|
||||
interface Bar {
|
||||
bar: string;
|
||||
}
|
||||
|
||||
export function fooToBar(
|
||||
foos: Record<string, Foo>
|
||||
): Record<string, Bar | null> {
|
||||
const wat = mapValues(foos, f => f.foo);
|
||||
const result = foos == null ? {} : mapValues(foos, f => f.foo);
|
||||
// This line _should_ fail, because `result` is not the right type.
|
||||
return result;
|
||||
~~~~~~~~~~~~~~
|
||||
!!! error TS2322: Type 'Dictionary<string>' is not assignable to type 'Record<string, Bar>'.
|
||||
!!! error TS2322: Index signatures are incompatible.
|
||||
!!! error TS2322: Type 'string' is not assignable to type 'Bar'.
|
||||
}
|
||||
|
||||
@@ -0,0 +1,60 @@
|
||||
//// [emptyObjectNotSubtypeOfIndexSignatureContainingObject2.ts]
|
||||
// This should behave the same as emptyObjectNotSubtypeOfIndexSignatureContainingObject1.ts
|
||||
// Begin types from Lodash.
|
||||
interface Dictionary<T> {
|
||||
[index: string]: T;
|
||||
}
|
||||
|
||||
interface NumericDictionary<T> {
|
||||
[index: number]: T;
|
||||
}
|
||||
|
||||
type ObjectIterator<TObject, TResult> = (
|
||||
value: TObject[keyof TObject],
|
||||
key: string,
|
||||
collection: TObject
|
||||
) => TResult;
|
||||
|
||||
type DictionaryIterator<T, TResult> = ObjectIterator<Dictionary<T>, TResult>;
|
||||
|
||||
// In lodash.d.ts this function has many overloads, but this seems to be the problematic one.
|
||||
function mapValues<T, TResult>(
|
||||
obj: Dictionary<T> | NumericDictionary<T> | null | undefined,
|
||||
callback: DictionaryIterator<T, TResult>
|
||||
): Dictionary<TResult> {
|
||||
return null as any;
|
||||
}
|
||||
// End types from Lodash.
|
||||
|
||||
interface Foo {
|
||||
foo: string;
|
||||
}
|
||||
|
||||
interface Bar {
|
||||
bar: string;
|
||||
}
|
||||
|
||||
export function fooToBar(
|
||||
foos: Record<string, Foo>
|
||||
): Record<string, Bar | null> {
|
||||
const wat = mapValues(foos, f => f.foo);
|
||||
const result = foos == null ? {} : mapValues(foos, f => f.foo);
|
||||
// This line _should_ fail, because `result` is not the right type.
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
//// [emptyObjectNotSubtypeOfIndexSignatureContainingObject2.js]
|
||||
"use strict";
|
||||
exports.__esModule = true;
|
||||
// In lodash.d.ts this function has many overloads, but this seems to be the problematic one.
|
||||
function mapValues(obj, callback) {
|
||||
return null;
|
||||
}
|
||||
function fooToBar(foos) {
|
||||
var wat = mapValues(foos, function (f) { return f.foo; });
|
||||
var result = foos == null ? {} : mapValues(foos, function (f) { return f.foo; });
|
||||
// This line _should_ fail, because `result` is not the right type.
|
||||
return result;
|
||||
}
|
||||
exports.fooToBar = fooToBar;
|
||||
@@ -0,0 +1,127 @@
|
||||
=== tests/cases/compiler/emptyObjectNotSubtypeOfIndexSignatureContainingObject2.ts ===
|
||||
// This should behave the same as emptyObjectNotSubtypeOfIndexSignatureContainingObject1.ts
|
||||
// Begin types from Lodash.
|
||||
interface Dictionary<T> {
|
||||
>Dictionary : Symbol(Dictionary, Decl(emptyObjectNotSubtypeOfIndexSignatureContainingObject2.ts, 0, 0))
|
||||
>T : Symbol(T, Decl(emptyObjectNotSubtypeOfIndexSignatureContainingObject2.ts, 2, 21))
|
||||
|
||||
[index: string]: T;
|
||||
>index : Symbol(index, Decl(emptyObjectNotSubtypeOfIndexSignatureContainingObject2.ts, 3, 3))
|
||||
>T : Symbol(T, Decl(emptyObjectNotSubtypeOfIndexSignatureContainingObject2.ts, 2, 21))
|
||||
}
|
||||
|
||||
interface NumericDictionary<T> {
|
||||
>NumericDictionary : Symbol(NumericDictionary, Decl(emptyObjectNotSubtypeOfIndexSignatureContainingObject2.ts, 4, 1))
|
||||
>T : Symbol(T, Decl(emptyObjectNotSubtypeOfIndexSignatureContainingObject2.ts, 6, 28))
|
||||
|
||||
[index: number]: T;
|
||||
>index : Symbol(index, Decl(emptyObjectNotSubtypeOfIndexSignatureContainingObject2.ts, 7, 3))
|
||||
>T : Symbol(T, Decl(emptyObjectNotSubtypeOfIndexSignatureContainingObject2.ts, 6, 28))
|
||||
}
|
||||
|
||||
type ObjectIterator<TObject, TResult> = (
|
||||
>ObjectIterator : Symbol(ObjectIterator, Decl(emptyObjectNotSubtypeOfIndexSignatureContainingObject2.ts, 8, 1))
|
||||
>TObject : Symbol(TObject, Decl(emptyObjectNotSubtypeOfIndexSignatureContainingObject2.ts, 10, 20))
|
||||
>TResult : Symbol(TResult, Decl(emptyObjectNotSubtypeOfIndexSignatureContainingObject2.ts, 10, 28))
|
||||
|
||||
value: TObject[keyof TObject],
|
||||
>value : Symbol(value, Decl(emptyObjectNotSubtypeOfIndexSignatureContainingObject2.ts, 10, 41))
|
||||
>TObject : Symbol(TObject, Decl(emptyObjectNotSubtypeOfIndexSignatureContainingObject2.ts, 10, 20))
|
||||
>TObject : Symbol(TObject, Decl(emptyObjectNotSubtypeOfIndexSignatureContainingObject2.ts, 10, 20))
|
||||
|
||||
key: string,
|
||||
>key : Symbol(key, Decl(emptyObjectNotSubtypeOfIndexSignatureContainingObject2.ts, 11, 32))
|
||||
|
||||
collection: TObject
|
||||
>collection : Symbol(collection, Decl(emptyObjectNotSubtypeOfIndexSignatureContainingObject2.ts, 12, 14))
|
||||
>TObject : Symbol(TObject, Decl(emptyObjectNotSubtypeOfIndexSignatureContainingObject2.ts, 10, 20))
|
||||
|
||||
) => TResult;
|
||||
>TResult : Symbol(TResult, Decl(emptyObjectNotSubtypeOfIndexSignatureContainingObject2.ts, 10, 28))
|
||||
|
||||
type DictionaryIterator<T, TResult> = ObjectIterator<Dictionary<T>, TResult>;
|
||||
>DictionaryIterator : Symbol(DictionaryIterator, Decl(emptyObjectNotSubtypeOfIndexSignatureContainingObject2.ts, 14, 13))
|
||||
>T : Symbol(T, Decl(emptyObjectNotSubtypeOfIndexSignatureContainingObject2.ts, 16, 24))
|
||||
>TResult : Symbol(TResult, Decl(emptyObjectNotSubtypeOfIndexSignatureContainingObject2.ts, 16, 26))
|
||||
>ObjectIterator : Symbol(ObjectIterator, Decl(emptyObjectNotSubtypeOfIndexSignatureContainingObject2.ts, 8, 1))
|
||||
>Dictionary : Symbol(Dictionary, Decl(emptyObjectNotSubtypeOfIndexSignatureContainingObject2.ts, 0, 0))
|
||||
>T : Symbol(T, Decl(emptyObjectNotSubtypeOfIndexSignatureContainingObject2.ts, 16, 24))
|
||||
>TResult : Symbol(TResult, Decl(emptyObjectNotSubtypeOfIndexSignatureContainingObject2.ts, 16, 26))
|
||||
|
||||
// In lodash.d.ts this function has many overloads, but this seems to be the problematic one.
|
||||
function mapValues<T, TResult>(
|
||||
>mapValues : Symbol(mapValues, Decl(emptyObjectNotSubtypeOfIndexSignatureContainingObject2.ts, 16, 77))
|
||||
>T : Symbol(T, Decl(emptyObjectNotSubtypeOfIndexSignatureContainingObject2.ts, 19, 19))
|
||||
>TResult : Symbol(TResult, Decl(emptyObjectNotSubtypeOfIndexSignatureContainingObject2.ts, 19, 21))
|
||||
|
||||
obj: Dictionary<T> | NumericDictionary<T> | null | undefined,
|
||||
>obj : Symbol(obj, Decl(emptyObjectNotSubtypeOfIndexSignatureContainingObject2.ts, 19, 31))
|
||||
>Dictionary : Symbol(Dictionary, Decl(emptyObjectNotSubtypeOfIndexSignatureContainingObject2.ts, 0, 0))
|
||||
>T : Symbol(T, Decl(emptyObjectNotSubtypeOfIndexSignatureContainingObject2.ts, 19, 19))
|
||||
>NumericDictionary : Symbol(NumericDictionary, Decl(emptyObjectNotSubtypeOfIndexSignatureContainingObject2.ts, 4, 1))
|
||||
>T : Symbol(T, Decl(emptyObjectNotSubtypeOfIndexSignatureContainingObject2.ts, 19, 19))
|
||||
|
||||
callback: DictionaryIterator<T, TResult>
|
||||
>callback : Symbol(callback, Decl(emptyObjectNotSubtypeOfIndexSignatureContainingObject2.ts, 20, 63))
|
||||
>DictionaryIterator : Symbol(DictionaryIterator, Decl(emptyObjectNotSubtypeOfIndexSignatureContainingObject2.ts, 14, 13))
|
||||
>T : Symbol(T, Decl(emptyObjectNotSubtypeOfIndexSignatureContainingObject2.ts, 19, 19))
|
||||
>TResult : Symbol(TResult, Decl(emptyObjectNotSubtypeOfIndexSignatureContainingObject2.ts, 19, 21))
|
||||
|
||||
): Dictionary<TResult> {
|
||||
>Dictionary : Symbol(Dictionary, Decl(emptyObjectNotSubtypeOfIndexSignatureContainingObject2.ts, 0, 0))
|
||||
>TResult : Symbol(TResult, Decl(emptyObjectNotSubtypeOfIndexSignatureContainingObject2.ts, 19, 21))
|
||||
|
||||
return null as any;
|
||||
}
|
||||
// End types from Lodash.
|
||||
|
||||
interface Foo {
|
||||
>Foo : Symbol(Foo, Decl(emptyObjectNotSubtypeOfIndexSignatureContainingObject2.ts, 24, 1))
|
||||
|
||||
foo: string;
|
||||
>foo : Symbol(Foo.foo, Decl(emptyObjectNotSubtypeOfIndexSignatureContainingObject2.ts, 27, 15))
|
||||
}
|
||||
|
||||
interface Bar {
|
||||
>Bar : Symbol(Bar, Decl(emptyObjectNotSubtypeOfIndexSignatureContainingObject2.ts, 29, 1))
|
||||
|
||||
bar: string;
|
||||
>bar : Symbol(Bar.bar, Decl(emptyObjectNotSubtypeOfIndexSignatureContainingObject2.ts, 31, 15))
|
||||
}
|
||||
|
||||
export function fooToBar(
|
||||
>fooToBar : Symbol(fooToBar, Decl(emptyObjectNotSubtypeOfIndexSignatureContainingObject2.ts, 33, 1))
|
||||
|
||||
foos: Record<string, Foo>
|
||||
>foos : Symbol(foos, Decl(emptyObjectNotSubtypeOfIndexSignatureContainingObject2.ts, 35, 25))
|
||||
>Record : Symbol(Record, Decl(lib.es5.d.ts, --, --))
|
||||
>Foo : Symbol(Foo, Decl(emptyObjectNotSubtypeOfIndexSignatureContainingObject2.ts, 24, 1))
|
||||
|
||||
): Record<string, Bar | null> {
|
||||
>Record : Symbol(Record, Decl(lib.es5.d.ts, --, --))
|
||||
>Bar : Symbol(Bar, Decl(emptyObjectNotSubtypeOfIndexSignatureContainingObject2.ts, 29, 1))
|
||||
|
||||
const wat = mapValues(foos, f => f.foo);
|
||||
>wat : Symbol(wat, Decl(emptyObjectNotSubtypeOfIndexSignatureContainingObject2.ts, 38, 7))
|
||||
>mapValues : Symbol(mapValues, Decl(emptyObjectNotSubtypeOfIndexSignatureContainingObject2.ts, 16, 77))
|
||||
>foos : Symbol(foos, Decl(emptyObjectNotSubtypeOfIndexSignatureContainingObject2.ts, 35, 25))
|
||||
>f : Symbol(f, Decl(emptyObjectNotSubtypeOfIndexSignatureContainingObject2.ts, 38, 29))
|
||||
>f.foo : Symbol(Foo.foo, Decl(emptyObjectNotSubtypeOfIndexSignatureContainingObject2.ts, 27, 15))
|
||||
>f : Symbol(f, Decl(emptyObjectNotSubtypeOfIndexSignatureContainingObject2.ts, 38, 29))
|
||||
>foo : Symbol(Foo.foo, Decl(emptyObjectNotSubtypeOfIndexSignatureContainingObject2.ts, 27, 15))
|
||||
|
||||
const result = foos == null ? {} : mapValues(foos, f => f.foo);
|
||||
>result : Symbol(result, Decl(emptyObjectNotSubtypeOfIndexSignatureContainingObject2.ts, 39, 7))
|
||||
>foos : Symbol(foos, Decl(emptyObjectNotSubtypeOfIndexSignatureContainingObject2.ts, 35, 25))
|
||||
>mapValues : Symbol(mapValues, Decl(emptyObjectNotSubtypeOfIndexSignatureContainingObject2.ts, 16, 77))
|
||||
>foos : Symbol(foos, Decl(emptyObjectNotSubtypeOfIndexSignatureContainingObject2.ts, 35, 25))
|
||||
>f : Symbol(f, Decl(emptyObjectNotSubtypeOfIndexSignatureContainingObject2.ts, 39, 52))
|
||||
>f.foo : Symbol(Foo.foo, Decl(emptyObjectNotSubtypeOfIndexSignatureContainingObject2.ts, 27, 15))
|
||||
>f : Symbol(f, Decl(emptyObjectNotSubtypeOfIndexSignatureContainingObject2.ts, 39, 52))
|
||||
>foo : Symbol(Foo.foo, Decl(emptyObjectNotSubtypeOfIndexSignatureContainingObject2.ts, 27, 15))
|
||||
|
||||
// This line _should_ fail, because `result` is not the right type.
|
||||
return result;
|
||||
>result : Symbol(result, Decl(emptyObjectNotSubtypeOfIndexSignatureContainingObject2.ts, 39, 7))
|
||||
}
|
||||
|
||||
@@ -0,0 +1,99 @@
|
||||
=== tests/cases/compiler/emptyObjectNotSubtypeOfIndexSignatureContainingObject2.ts ===
|
||||
// This should behave the same as emptyObjectNotSubtypeOfIndexSignatureContainingObject1.ts
|
||||
// Begin types from Lodash.
|
||||
interface Dictionary<T> {
|
||||
[index: string]: T;
|
||||
>index : string
|
||||
}
|
||||
|
||||
interface NumericDictionary<T> {
|
||||
[index: number]: T;
|
||||
>index : number
|
||||
}
|
||||
|
||||
type ObjectIterator<TObject, TResult> = (
|
||||
>ObjectIterator : ObjectIterator<TObject, TResult>
|
||||
|
||||
value: TObject[keyof TObject],
|
||||
>value : TObject[keyof TObject]
|
||||
|
||||
key: string,
|
||||
>key : string
|
||||
|
||||
collection: TObject
|
||||
>collection : TObject
|
||||
|
||||
) => TResult;
|
||||
|
||||
type DictionaryIterator<T, TResult> = ObjectIterator<Dictionary<T>, TResult>;
|
||||
>DictionaryIterator : ObjectIterator<Dictionary<T>, TResult>
|
||||
|
||||
// In lodash.d.ts this function has many overloads, but this seems to be the problematic one.
|
||||
function mapValues<T, TResult>(
|
||||
>mapValues : <T, TResult>(obj: Dictionary<T> | NumericDictionary<T>, callback: ObjectIterator<Dictionary<T>, TResult>) => Dictionary<TResult>
|
||||
|
||||
obj: Dictionary<T> | NumericDictionary<T> | null | undefined,
|
||||
>obj : Dictionary<T> | NumericDictionary<T>
|
||||
>null : null
|
||||
|
||||
callback: DictionaryIterator<T, TResult>
|
||||
>callback : ObjectIterator<Dictionary<T>, TResult>
|
||||
|
||||
): Dictionary<TResult> {
|
||||
return null as any;
|
||||
>null as any : any
|
||||
>null : null
|
||||
}
|
||||
// End types from Lodash.
|
||||
|
||||
interface Foo {
|
||||
foo: string;
|
||||
>foo : string
|
||||
}
|
||||
|
||||
interface Bar {
|
||||
bar: string;
|
||||
>bar : string
|
||||
}
|
||||
|
||||
export function fooToBar(
|
||||
>fooToBar : (foos: Record<string, Foo>) => Record<string, Bar>
|
||||
|
||||
foos: Record<string, Foo>
|
||||
>foos : Record<string, Foo>
|
||||
|
||||
): Record<string, Bar | null> {
|
||||
>null : null
|
||||
|
||||
const wat = mapValues(foos, f => f.foo);
|
||||
>wat : Dictionary<string>
|
||||
>mapValues(foos, f => f.foo) : Dictionary<string>
|
||||
>mapValues : <T, TResult>(obj: Dictionary<T> | NumericDictionary<T>, callback: ObjectIterator<Dictionary<T>, TResult>) => Dictionary<TResult>
|
||||
>foos : Record<string, Foo>
|
||||
>f => f.foo : (f: Foo) => string
|
||||
>f : Foo
|
||||
>f.foo : string
|
||||
>f : Foo
|
||||
>foo : string
|
||||
|
||||
const result = foos == null ? {} : mapValues(foos, f => f.foo);
|
||||
>result : Dictionary<string>
|
||||
>foos == null ? {} : mapValues(foos, f => f.foo) : Dictionary<string>
|
||||
>foos == null : boolean
|
||||
>foos : Record<string, Foo>
|
||||
>null : null
|
||||
>{} : {}
|
||||
>mapValues(foos, f => f.foo) : Dictionary<string>
|
||||
>mapValues : <T, TResult>(obj: Dictionary<T> | NumericDictionary<T>, callback: ObjectIterator<Dictionary<T>, TResult>) => Dictionary<TResult>
|
||||
>foos : Record<string, Foo>
|
||||
>f => f.foo : (f: Foo) => string
|
||||
>f : Foo
|
||||
>f.foo : string
|
||||
>f : Foo
|
||||
>foo : string
|
||||
|
||||
// This line _should_ fail, because `result` is not the right type.
|
||||
return result;
|
||||
>result : Dictionary<string>
|
||||
}
|
||||
|
||||
@@ -0,0 +1,42 @@
|
||||
// This should behave the same as emptyObjectNotSubtypeOfIndexSignatureContainingObject2.ts
|
||||
// Begin types from Lodash.
|
||||
interface Dictionary<T> {
|
||||
[index: string]: T;
|
||||
}
|
||||
|
||||
interface NumericDictionary<T> {
|
||||
[index: number]: T;
|
||||
}
|
||||
|
||||
type ObjectIterator<TObject, TResult> = (
|
||||
value: TObject[keyof TObject],
|
||||
key: string,
|
||||
collection: TObject
|
||||
) => TResult;
|
||||
|
||||
type DictionaryIterator<T, TResult> = ObjectIterator<Dictionary<T>, TResult>;
|
||||
|
||||
// In lodash.d.ts this function has many overloads, but this seems to be the problematic one.
|
||||
function mapValues<T, TResult>(
|
||||
obj: Dictionary<T> | NumericDictionary<T> | null | undefined,
|
||||
callback: DictionaryIterator<T, TResult>
|
||||
): Dictionary<TResult> {
|
||||
return null as any;
|
||||
}
|
||||
// End types from Lodash.
|
||||
|
||||
interface Foo {
|
||||
foo: string;
|
||||
}
|
||||
|
||||
interface Bar {
|
||||
bar: string;
|
||||
}
|
||||
|
||||
export function fooToBar(
|
||||
foos: Record<string, Foo>
|
||||
): Record<string, Bar | null> {
|
||||
const result = foos == null ? {} : mapValues(foos, f => f.foo);
|
||||
// This line _should_ fail, because `result` is not the right type.
|
||||
return result;
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
// This should behave the same as emptyObjectNotSubtypeOfIndexSignatureContainingObject1.ts
|
||||
// Begin types from Lodash.
|
||||
interface Dictionary<T> {
|
||||
[index: string]: T;
|
||||
}
|
||||
|
||||
interface NumericDictionary<T> {
|
||||
[index: number]: T;
|
||||
}
|
||||
|
||||
type ObjectIterator<TObject, TResult> = (
|
||||
value: TObject[keyof TObject],
|
||||
key: string,
|
||||
collection: TObject
|
||||
) => TResult;
|
||||
|
||||
type DictionaryIterator<T, TResult> = ObjectIterator<Dictionary<T>, TResult>;
|
||||
|
||||
// In lodash.d.ts this function has many overloads, but this seems to be the problematic one.
|
||||
function mapValues<T, TResult>(
|
||||
obj: Dictionary<T> | NumericDictionary<T> | null | undefined,
|
||||
callback: DictionaryIterator<T, TResult>
|
||||
): Dictionary<TResult> {
|
||||
return null as any;
|
||||
}
|
||||
// End types from Lodash.
|
||||
|
||||
interface Foo {
|
||||
foo: string;
|
||||
}
|
||||
|
||||
interface Bar {
|
||||
bar: string;
|
||||
}
|
||||
|
||||
export function fooToBar(
|
||||
foos: Record<string, Foo>
|
||||
): Record<string, Bar | null> {
|
||||
const wat = mapValues(foos, f => f.foo);
|
||||
const result = foos == null ? {} : mapValues(foos, f => f.foo);
|
||||
// This line _should_ fail, because `result` is not the right type.
|
||||
return result;
|
||||
}
|
||||
Reference in New Issue
Block a user